1 Data description

In this tutorial, we aim to obtain differentially expressed genes between two biological conditions in an integrated data. This integrated data set is generated by combining 10 microarray studies on control and TGFb-treated samples (for more information, see here http://mcr.aacrjournals.org/content/15/5/619). 

First, we assess the presence of unwanted variation in the integrated data which combines differents studies and platforms. Second, we show how to use two RUV methods: RUVinv and RUV4 to remove unwanted variation and detect differentially expressed genes comparing control samples to TGFb-treated samples. Third, we assess whether RUV methods are useful and compare the results obtained by each method.

library(ruv)
Error in library(ruv) : there is no package called ‘ruv’

The integrated data introduced above have been split into two data sets: samples A and samples B, each containing different studies, platforms and tissues. We will explore and normalise these two data sets separately in order to compare the results obtained by the two normalisation methods (RUV4 and RUVinv).

Read in the two integrated datasets.

rr

samplesA<- read.table(\expr_10data_sampleA.txt\, header = T, sep = \\t\)
samplesB<- read.table(\expr_10data_sampleB.txt\, header = T, sep = \\t\)

Look at the data in each samples A and B, then make a matrix for each these data where the row names are gene IDs.

rr

head(samplesA,3)
head(samplesB,3)

r

mA<-samplesA[,2:dim(samplesA)[2]]
mB<-samplesB[,2:dim(samplesB)[2]]
row.names(mA)<- samplesA[,1]
row.names(mB)<- samplesB[,1]
mA<- as.matrix(mA)
mB<- as.matrix(mB)

Look at the information related to each sample including the name of the studies, types of platform, treatment, and tissue:

info_samplesA<- read.table("info_10data_sampleA.txt", sep="\t", header=T)
info_samplesA
info_samplesB<- read.table("info_10data_sampleB.txt", sep="\t", header=T)
info_samplesB

2 Assessment of unwanted variation in the data

Here we perform some exploratory analysis on the integrated data to assess the presence of unwanted variation in each dataset.

2.1 RLE plot

We start by looking at the RLE plots in samples A data, coloured by study, platform and tissue:

## Transpose the expression matrix so that we have genes in columns and samples in rows
YA <- t(mA)
## Plot RLE coloured by study
ruv_rle(YA, info_samplesA$study, ylim = c(-4,4))

## Plot RLE coloured by platform
ruv_rle(YA, info_samplesA$platform, ylim = c(-4,4))

## Plot RLE coloured by platform
ruv_rle(YA, info_samplesA$tissue, ylim = c(-4,4))

Similarly, we look at the RLE plots in sample B data coloured by study, platform and tissue:

YB <- t(mB)
## Plot RLE coloured by study
ruv_rle(YB, info_samplesB$study, ylim = c(-4,4))
## Plot RLE coloured by platform
ruv_rle(YB, info_samplesB$platform, ylim = c(-4,4))

## Plot RLE coloured by tissue
ruv_rle(YB, info_samplesB$tissue, ylim = c(-4,4))

2.2 PCA plot

In transcriptomics applications, one of the most utilized exploratory plots is the multi-dimensional scaling (MDS) plot or a principal component analysis (PCA) plot. To assess the presence of unwanted variation in each sample, we use PCA plots to show similarities between samples measured in an unsupervised way. Ideally, samples should cluster together according to the treatment (i.e. the biological factor of interest). Here, we see that samples are rather clustered by studies (i.e. unwanted variation) in both samples A and B data.
In the current example, it’s important to note that in some cases, different studies are confounded with different platforms and tissues, and therefore there is no way to identify how much of the unwanted variation come from each of these factors. Such situations must be avoided when designing an experiment and for the purpose of this tutorial, we only consider “study” as the source of unwanted variation.

3 Remove batch effects using RUV methods

There are several RUV methods for removing unwanted variation in order to obtain DEGs; these include RUV-2, RUV-4, RUV-inv and RUV-rinv. In general, RUV methods are dependent on negative control genes (genes which are not associated with the biological factor of interest) and replicate samples (if applicable). RUV-2 removes unwanted variation in two steps. RUV-4 came after RUV-2 and has four steps. For RUV-4 we can estimate the dimension of unwanted variation (k) or select different values for k, while for RUV-inv and RUV-rinv we don’t need to estimate k as it is set to be the maximum value. In general, RUV-inv and RUV-rinv are better than RUV-4. RUV-inv is recommended when we have large number of control genes (~1000), while RUV-rinv is more appropriate with small number of control genes (~60).
Selection of negative control genes is very important. Examples of negative control genes are the spike-in controls or the housekeeping (HK) genes. It is also possible to define empirical negative control genes using an iterative approach. However, it is only recomended if (i) the initial negative control genes are not very good or there are only a few of them; (ii) the beta seems to be very sparse. Therefore, the user needs to generate diagnostic plots to assess the performance of the initial analysis, and only if needed, use an iterative approach to define better control genes.

3.1 RUVinv

Here, we first focus on RUV-inv, which is performed by RUVinv() function. This function take expression matrix (Y), biological factor of interest (X), and a vector for indices of negative control genes (ctl).

3.1.1 Apply RUVinv using house-keeping genes

We begin with the list of housekeeping (HK) genes as our negative controls.

rr

# library(ruv)
HKgenes<- read.table(\HouseKeeping_genes_IDs.txt\, header=T, sep=\\t\)
hk<- HKgenes$GeneID
matA<- t(mA)
matB<- t(mB)
ctrl<- colnames(matA) %in% hk

We run RUVinv using HK genes on samples A data.

Check if HK genes as negative control genes in the initial analysis were useful.

## Look at the distribution of p-values
ruv_hist(fit_ruvin_hk_samplesA.summary)

## Look at the volcano plot
genecoloring <- list(aes(color = Categ),
                     scale_color_manual(name = "Gene Category",
                                        values = alpha(c("Red", "black"),
                                                     c( 0.25, 0.1))))
ruv_volcano(fit_ruvin_hk_samplesA.summary) + genecoloring

## Look at ECDF of p-values
ruv_ecdf(fit_ruvin_hk_samplesA.summary) + genecoloring

Similarly, we run RUVinv using HK genes on samples B data.

Check if HK genes as negative control genes in the initial analysis were useful.

## Look at the distribution of p-values
ruv_hist(fit_ruvin_hk_samplesB.summary)

## Look at the volcano plot
genecoloring <- list(aes(color = fit.ctl),
                     scale_color_manual(name = "Gene Category",
                                        values = alpha(c("Red", "black"),
                                                     c( 0.1, 0.25))))
ruv_volcano(fit_ruvin_hk_samplesB.summary) + genecoloring

genecoloring <- list(aes(color = Categ),
                     scale_color_manual(name = "Gene Category",
                                        values = alpha(c("Red", "black"),
                                                     c( 0.25, 0.1))))
ruv_volcano(fit_ruvin_hk_samplesB.summary) + genecoloring

## Look at ECDF of p-values
ruv_ecdf(fit_ruvin_hk_samplesB.summary) + genecoloring

3.1.2 Apply RUVinv using empirical control genes

According to the above results, some of the HK genes seem to be differentially expressed. In these cases, it is often recomended to use RUV4 as we can manually change the k, where smaller k may retain more of the biological signal and larger k may overadjust the data. For now, we continue with RUVinv to show how to define empirical negative control genes, by selecting those genes that were not statistically significant in the results of teh initital analysis. Next, we show the use of RUV4 on these data.

## Selecting empirical negative controls genes
cGenes_samplesA <- row.names(fit_ruvin_hk_samplesA.summary$C)[fit_ruvin_hk_samplesA.summary$C$F.p.BH > 0.05]  
length(cGenes_samplesA)
[1] 7916
empCtrl_ruvinv_samplesA <- colnames(YA) %in% cGenes_samplesA
Gene_Category <- empCtrl_ruvinv_samplesA
Gene_Category[empCtrl_ruvinv_samplesA == T] <- "EmpCtl"
Gene_Category[empCtrl_ruvinv_samplesA == F] <- "Non_EmpCtl"
Emp_Ct_Genes_samplesA <- data.frame(geneids = colnames(YA),
                                    empCt_RUV = empCtrl_ruvinv_samplesA,
                                    Categ = Gene_Category)
head(Emp_Ct_Genes_samplesA)

And similarly for sample B:

## Select empirical negative controls genes
cGenes_samplesB <- row.names(fit_ruvin_hk_samplesB.summary$C)[fit_ruvin_hk_samplesB.summary$C$F.p.BH > 0.05]
length(cGenes_samplesB)
[1] 8919
empCtrl_ruvinv_samplesB<- colnames(YB) %in% cGenes_samplesB
Gene_Category <- empCtrl_ruvinv_samplesB
Gene_Category[empCtrl_ruvinv_samplesB==T]="EmpCtl"
Gene_Category[empCtrl_ruvinv_samplesB==F]="Non_EmpCtl"
Emp_Ct_Genes_samplesB <- data.frame(geneids = colnames(matB),
                                    empCt_RUV = empCtrl_ruvinv_samplesB,
                                    Categ = Gene_Category)
head(Emp_Ct_Genes_samplesB)

Now we use those empirical control genes to apply RUVinv in samples A and B data sets.

##---- In samples A data:
fit_ruvin_emp_samplesA <- RUVinv(Y = YA, X = gA, 
                                 ctl = Emp_Ct_Genes_samplesA$empCt_RUV,
                                 Z = 1, fullW0 = NULL, 
                                 lambda = NULL, iterN = 100000)
fit_ruvin_emp_samplesA.summary <- ruv_summary(YA, fit_ruvin_emp_samplesA, 
                                             info_samplesA,              ## row info
                                             Emp_Ct_Genes_samplesA)      ## col info
##---- In samples B data: 
fit_ruvin_emp_samplesB <- RUVinv(Y = YB, X = gB, 
                                ctl = Emp_Ct_Genes_samplesB$empCt_RUV, 
                                Z = 1, fullW0 = NULL, 
                                lambda = NULL, iterN = 100000)
fit_ruvin_emp_samplesB.summary <- ruv_summary(YB, fit_ruvin_emp_samplesB, 
                                             info_samplesB, 
                                             Emp_Ct_Genes_samplesB)

Here, we look at the statistics obtained for samples A data.

## Look at the distribution of p-values
ruv_hist(fit_ruvin_emp_samplesA.summary)

## Look at the Volcano plot
genecoloring <- list(aes(color = Categ), 
                    scale_color_manual(name = "Gene Category",
                                       values = alpha(c("Black", "red"),
                                                      c( 0.1, 0.25))))
ruv_volcano(fit_ruvin_emp_samplesA.summary) + genecoloring

## Look at ECDF of p-values
ruv_ecdf(fit_ruvin_emp_samplesA.summary) + genecoloring

Now we look at the statistics obtained for samples B data.

## Look at the distribution of p-values
ruv_hist(fit_ruvin_emp_samplesB.summary)

## Look at the volcano plot
genecoloring <- list(aes(color = Categ),
                    scale_color_manual(name = "Gene Category",
                                       values = alpha(c("Black","Red"),
                                                    c( 0.2, 0.2))))
ruv_volcano(fit_ruvin_emp_samplesB.summary) + genecoloring

## Look at ECDF of p-values
ruv_ecdf(fit_ruvin_emp_samplesB.summary) + genecoloring

3.2 RUV4

RUV4 can be run with different values of k in an attempt to find the optimal value. Note that although there is a function to estimate k, called getK(), this may not give the optimal value for k and is often recomended to be used when there is no other choice but to automate finding K (e.g. in simulations).

3.2.1 Apply RUV4 using empirical control genes

Run RUV4 using different values of k and emprical controls.


## Instead of estimating k (commented below), we look at different values for k.
# estimateK<- getK(YA, X=gA,
#                  ctl=Emp_Ct_Genes_samplesA$empCt_RUV,
#                  Z = 1, eta = NULL, fullW0 = NULL, cutoff = NULL,
#                  method="select", l=1, inputcheck = TRUE)
# kA <- estimateK$k   ## it will be k = 11

# estimateK<- getK(YB, X=gB,
#                  ctl=Emp_Ct_Genes_samplesB$empCt_RUV,
#                  Z = 1, eta = NULL, fullW0 = NULL, cutoff = NULL,
#                  method="select", l=1, inputcheck = TRUE)
# kB <- estimateK$k   ## it will be k = 8

ks <- c(1, 2, 5, 6, 7, 8, 10, 11, 12, 15, 18, 20, 22, 23, 24)
## For k > 24 I got Error:
# NaNs producedNaNs producedError in sigmashrink(fit$sigma2, fit$df) : 
#   NA/NaN/Inf in foreign function call (arg 1)

beta_corAB <- vector()

for (K in ks){
  fit_ruv4_emp_sampleA <- RUV4(YA, X = gA, 
                            ctl = Emp_Ct_Genes_samplesA$empCt_RUV, 
                            k = K,Z = 1, eta = NULL, 
                            fullW0 = NULL, inputcheck = TRUE)
  
  fit_ruv4_emp_sampleA.summary <- ruv_summary(YA,
                                           fit_ruv4_emp_sampleA,
                                           info_samplesA,
                                           Emp_Ct_Genes_samplesA)
  
  fit_ruv4_emp_sampleB <- RUV4(YB, X = gB, 
                            ctl = Emp_Ct_Genes_samplesB$empCt_RUV, 
                            k = K,Z = 1, eta = NULL, 
                            fullW0 = NULL, inputcheck = TRUE)
  
  fit_ruv4_emp_sampleB.summary <- ruv_summary(YB,
                                           fit_ruv4_emp_sampleB,
                                           info_samplesB,
                                           Emp_Ct_Genes_samplesB)
  
  currentCor <- cor.test(fit_ruv4_emp_sampleA$betahat,
                        fit_ruv4_emp_sampleB$betahat)$estimate
  
  beta_corAB <- c(beta_corAB, currentCor)
  
}
names(beta_corAB) <- ks
beta_corAB ## K = 23 seems a good choice

3.2.2 Apply RUV4 using house-keeping genes


## Instead of estimating k (commented below), we look at different values for k.
# estimateK<- getK(YA, X = gA,
#                  ctl = ctrl,
#                  Z = 1, eta = NULL, fullW0 = NULL, cutoff = NULL,
#                  method="select", l=1, inputcheck = TRUE)
# kA <- estimateK$k   ## it will be k = 7
# 
# estimateK<- getK(YB, X = gB,
#                  ctl = ctrl,
#                  Z = 1, eta = NULL, fullW0 = NULL, cutoff = NULL,
#                  method="select", l=1, inputcheck = TRUE)
# kB <- estimateK$k   ## it will be k = 6

ks <- c(1, 2, 5, 6, 7, 8, 10, 11, 12, 15, 18, 20, 22, 23, 24)
## For k > 24 I got Error:
# NaNs producedNaNs producedError in sigmashrink(fit$sigma2, fit$df) : 
#   NA/NaN/Inf in foreign function call (arg 1)

beta_corAB_HK <- vector()

for (K in ks){
  fit_ruv4_hk_sampleA <- RUV4(YA, X = gA, 
                            ctl = ctrl, 
                            k = K,Z = 1, eta = NULL, 
                            fullW0 = NULL, inputcheck = TRUE)
  
  fit_ruv4_hk_sampleA.summary <- ruv_summary(YA,
                                           fit_ruv4_hk_sampleA,
                                           info_samplesA)
  
  fit_ruv4_hk_sampleB <- RUV4(YB, X = gB, 
                            ctl = ctrl, 
                            k = K,Z = 1, eta = NULL, 
                            fullW0 = NULL, inputcheck = TRUE)
  
  fit_ruv4_hk_sampleB.summary <- ruv_summary(YB,
                                           fit_ruv4_hk_sampleB,
                                           info_samplesB)
  
  currentCor <- cor.test(fit_ruv4_hk_sampleA$betahat,
                        fit_ruv4_hk_sampleB$betahat)$estimate
  
  beta_corAB_HK <- c(beta_corAB_HK, currentCor)
  
}
names(beta_corAB_HK) <- ks
beta_corAB_HK ## K = 23 seems a good choice

As k = 23 results in the highest correlation between samples A and B data sets, we consider that as the optimal value, and we run RUV4 using k = 23.


##------ If using EmpCtrl:
K = 23
fit_ruv4_emp_sampleA <- RUV4(YA, X = gA, 
                          ctl = Emp_Ct_Genes_samplesA$empCt_RUV, 
                          k = K,Z = 1, eta = NULL, 
                          fullW0 = NULL, inputcheck = TRUE)

fit_ruv4_emp_sampleA.summary <- ruv_summary(YA,
                                         fit_ruv4_emp_sampleA,
                                         info_samplesA,
                                         Emp_Ct_Genes_samplesA)

fit_ruv4_emp_sampleB <- RUV4(YB, X = gB, 
                          ctl = Emp_Ct_Genes_samplesB$empCt_RUV, 
                          k = K,Z = 1, eta = NULL, 
                          fullW0 = NULL, inputcheck = TRUE)

fit_ruv4_emp_sampleB.summary <- ruv_summary(YB,
                                         fit_ruv4_emp_sampleB,
                                         info_samplesB,
                                         Emp_Ct_Genes_samplesB)

##------- If using HK genes:
fit_ruv4_hk_sampleA <- RUV4(YA, X = gA, 
                          ctl = ctrl, 
                          k = K,Z = 1, eta = NULL, 
                          fullW0 = NULL, inputcheck = TRUE)

fit_ruv4_hk_sampleA.summary <- ruv_summary(YA,
                                         fit_ruv4_hk_sampleA,
                                         info_samplesA)

fit_ruv4_hk_sampleB <- RUV4(YB, X = gB, 
                          ctl = ctrl, 
                          k = K,Z = 1, eta = NULL, 
                          fullW0 = NULL, inputcheck = TRUE)

fit_ruv4_hk_sampleB.summary <- ruv_summary(YB,
                                         fit_ruv4_hk_sampleB,
                                         info_samplesB)

4 Comparison of results of unadjusted, RUVinv- and RUV4-adjusted data

In order to see if we have helped or not, we run differential expression analysis on the unadjusted data. Then we compare the results of RUVinv, RUV4 and unadjusted together.

4.1 Unadjusted data

We can run RUV4 with k = 0 to do no adjustment when obtaining DEGs.

4.1.1 Apply DE analysis in the unadjusted data using HK genes

# RUV4 with k = 0 for no adjustment
# Equivalent to a Limma Analysis without considering the batch term
##----- In sample A data
fit_unadj_hk_sampleA <- RUV4(YA, X = gA, 
                          ctl = ctrl, 
                          k = 0)
fit_unadj_hk_sampleA.summary <- ruv_summary(YA, 
                                        fit_unadj_hk_sampleA,
                                        info_samplesA)
##----- In sample B data
fit_unadj_hk_sampleB <- RUV4(YB, X = gB, 
                          ctl = ctrl,
                          k = 0)
fit_unadj_hk_sampleB.summary <- ruv_summary(YB, 
                                         fit_unadj_hk_sampleB,
                                         info_samplesB)

4.1.2 Apply DE analysis in the unadjusted data using empirical control genes

# RUV4 with k = 0 for no adjustment
# Equivalent to a Limma Analysis without considering the batch term
##----- In sample A data
fit_unadj_emp_sampleA <- RUV4(YA, X = gA, 
                          ctl = Emp_Ct_Genes_samplesA$empCt_RUV, 
                          k = 0)
fit_unadj_emp_sampleA.summary <- ruv_summary(YA, 
                                        fit_unadj_emp_sampleA,
                                        info_samplesA, 
                                        Emp_Ct_Genes_samplesA)
##----- In sample B data
fit_unadj_emp_sampleB <- RUV4(YB, X = gB, 
                          ctl = Emp_Ct_Genes_samplesB$empCt_RUV, 
                          k = 0)
fit_unadj_emp_sampleB.summary <- ruv_summary(YB, 
                                         fit_unadj_emp_sampleB,
                                         info_samplesB,
                                         Emp_Ct_Genes_samplesB)

4.2 P-values distribution

We compare the results obtained from unajusted, RUVinv- and RUV4- adjusted data using p-value distributions, correlations of beta values and venn diagrams in samples A and B data.

4.3 Betahat correlation

For each of the unadjusted, RUVinv- and RUV4- adjusted settings, we can compare the results between samples A and B data sets to see which method gives more consistent resulst in these two data sets. To quantify these consistencies, we look at the correlations between betahat from sample A and betahat from sample B for the unadjusted method, RUVinv and RUV4.

##------ Unadjusted data sets
plot(fit_unadj_emp_sampleA$betahat, 
     fit_unadj_emp_sampleB$betahat,
     xlab = "Betahat Samples A",
     ylab = "Betahat Samples B",
     main = "Unadjusted",
     xlim = c(-3,3), cex = 0.3, ylim = c(-4,4))
# abline(fit_unadj_emp_sampleB$betahat,fit_unadj_emp_sampleA$betahat)
corVal <- cor.test(fit_unadj_emp_sampleA$betahat, fit_unadj_emp_sampleB$betahat)$estimate
text(-3,3, pos = 4, paste("Correlation: ", round(corVal,2), sep = ""))

##------ RUVinv adjusted data sets
plot(fit_ruvin_emp_samplesA$betahat,
     fit_ruvin_emp_samplesB$betahat,
     xlab = "Betahat Samples A",
     ylab = "Betahat Samples B",
     main = "RUVinv",
     xlim = c(-3,3), cex=0.3, ylim=c(-4,4))
#abline(fit_ruvin_emp_samplesB$betahat,fit_ruvin_emp_samplesA$betahat)
corVal <- cor.test(fit_ruvin_emp_samplesA$betahat, fit_ruvin_emp_samplesB$betahat)$estimate
text(-3,3, pos = 4, paste("Correlation: ", round(corVal,2), sep = ""))

#------- RUV4 adjusted data sets
plot(fit_ruv4_emp_sampleA$betahat,
     fit_ruv4_emp_sampleB$betahat,
     xlab = "Betahat Samples A",
     ylab = "Betahat Samples B",
     main = "RUV4",
     xlim = c(-3,3), cex = 0.3, ylim = c(-4,4))
#abline(fit_ruv4_emp_sampleB$betahat,fit_ruv4_emp_sampleA$betahat)
corVal <- cor.test(fit_ruv4_emp_sampleA$betahat, fit_ruv4_emp_sampleB$betahat)$estimate
text(-3,3, pos=4, paste("Correlation: ", round(corVal,2),sep=""))

4.4 Overlap between differentially expressed genes

Finally, for each of the unadjusted, RUVinv and RUV4, we look at the number of overlapping differentially expressed genes (DEGs) between the two samples A and B data sets. We also check for consistency between methods on the same data (sample A or sample B data set).
First, we define DEGs as genes with adjusted p-value < 0.05 and |logFC| > 1 in samples A and B data sets which are unadjusted, RUV4- or RUVinv-adjusted.

DEGsUnadj_sampleA <- row.names(fit_unadj_emp_sampleA.summary$C)
[fit_unadj_emp_sampleA.summary$C$F.p.BH < 0.05 &
Error: unexpected '[' in "["

4.4.1 DEGs in the unadjusted data

Venn diagram comparing the unadjusted samples A and B data.

allDEGs_unadj <- c(DEGsUnadj_sampleA, 
                    DEGsUnadj_sampleB)
## remove duplicated gene symbols:
allDEGs_unadj <- allDEGs_unadj[!duplicated(allDEGs_unadj)]  
## Draw a Venn diagram comparing DEGs for RUVinv
Counts_unadj <- matrix(0, nrow = length(allDEGs_unadj), ncol = 2)
row.names(Counts_unadj)<- allDEGs_unadj
colnames(Counts_unadj)<- c("Unadj_A","Unadj_B")
for( i in 1:length(allDEGs_unadj)) {
  Counts_unadj[i,1]<- allDEGs_unadj[i] %in% DEGsUnadj_sampleA
  Counts_unadj[i,2]<- allDEGs_unadj[i] %in% DEGsUnadj_sampleB
}
col <- c("blue", "violet")
vennDiagram(vennCounts(Counts_unadj), 
            circle.col = col, 
            cex = c(1.6, 1.2, 1), lwd=2)

4.4.2 DEGs in the RUVinv-adjusted data

Venn diagram comparing the RUVinv-adjusted samples A and B data.

allDEGs_RUVinv <- c(DEGsRUVinv_sampleA, 
                    DEGsRUVinv_sampleB)
## remove duplicated gene symbols:
allDEGs_RUVinv <- allDEGs_RUVinv[!duplicated(allDEGs_RUVinv)]  
## Draw a Venn diagram comparing DEGs for RUVinv
Counts_RUVinv <- matrix(0, nrow = length(allDEGs_RUVinv), ncol = 2)
row.names(Counts_RUVinv)<- allDEGs_RUVinv
colnames(Counts_RUVinv)<- c("RUVinv_A","RUVinv_B")
for( i in 1:length(allDEGs_RUVinv)) {
  Counts_RUVinv[i,1]<- allDEGs_RUVinv[i] %in% DEGsRUVinv_sampleA
  Counts_RUVinv[i,2]<- allDEGs_RUVinv[i] %in% DEGsRUVinv_sampleB
}
col<- c("blue", "violet")
vennDiagram(vennCounts(Counts_RUVinv), 
            circle.col = col,
            cex = c(1.6, 1.2, 1), lwd = 2)

4.4.3 DEGs in the RUV4-adjusted data

Venn diagram comparing the RUV4-adjusted samples A and B data.

allDEGs_RUV4<- c(DEGsRUV4_sampleA, DEGsRUV4_sampleB)
## remove duplicated gene symbols:
allDEGs_RUV4<- allDEGs_RUV4[!duplicated(allDEGs_RUV4)]  
## Draw a Venn diagram comparing DEGs for RUV4
Counts_RUV4 <- matrix(0, nrow= length(allDEGs_RUV4), ncol=2)
row.names(Counts_RUV4)<- allDEGs_RUV4
colnames(Counts_RUV4)<- c("RUV4_A","RUV4_B")
for( i in 1:length(allDEGs_RUV4)) {
  Counts_RUV4[i,1]<- allDEGs_RUV4[i] %in% DEGsRUV4_sampleA
  Counts_RUV4[i,2]<- allDEGs_RUV4[i] %in% DEGsRUV4_sampleB
}
col<- c("blue", "violet")
vennDiagram(vennCounts(Counts_RUV4), 
            circle.col = col, 
            cex = c(1.6, 1.2, 1), lwd = 2)

4.4.4 Compare the unadjusted, RUV4 and RUVinv-adjusted in samples A data

4.4.5 Compare the unadjusted, RUV4 and RUVinv-adjusted in samples B data

allDEGs_sampleB <- c(DEGsUnadj_sampleB,
                     DEGsRUVinv_sampleB,
                     DEGsRUV4_sampleB)
## remove duplicated gene symbols:
allDEGs_sampleB <- allDEGs_sampleB[!duplicated(allDEGs_sampleB)] 
## Draw a Venn diagram comparing DEGs for sample B
Counts_sampleB <- matrix(0, nrow = length(allDEGs_sampleB), ncol = 3)
row.names(Counts_sampleB) <- allDEGs_sampleB
colnames(Counts_sampleB) <- c("Unadj_B", "RUVinv_B","Ruv4_B")
for( i in 1:length(allDEGs_sampleB)) {
  Counts_sampleB[i,1]<- allDEGs_sampleB[i] %in% DEGsUnadj_sampleB
  Counts_sampleB[i,2]<- allDEGs_sampleB[i] %in% DEGsRUVinv_sampleB
  Counts_sampleB[i,3]<- allDEGs_sampleB[i] %in% DEGsRUV4_sampleB
}
col <- c("blue", "violet", "darkgreen")
vennDiagram(vennCounts(Counts_sampleB), 
            circle.col = col, 
            cex = c(1.6, 1.2, 1), lwd = 2)

LS0tCnRpdGxlOiAiSG93IHRvIHJlbW92ZSB1bndhbnRlZCB2YXJpYXRpb24gZnJvbSB0cmFuc2NyaXB0b21pY3MgZGF0YSB1c2luZyBSVVZpbnYgYW5kIFJVVjQiCmF1dGhvcjogU2VwaWRlaCBGb3JvdXRhbiBhbmQgTWFyaWUgVHJ1c3NhcnQKb3V0cHV0OgogIGdpdGh1Yl9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgaHRtbF9ub3RlYm9vazoKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIGNvZGVfZm9sZGluZzogImhpZGUiCiAgICBmaWdfY2FwdGlvbjogeWVzCi0tLQoKCiMgRGF0YSBkZXNjcmlwdGlvbgpJbiB0aGlzIHR1dG9yaWFsLCB3ZSBhaW0gdG8gb2J0YWluIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyBiZXR3ZWVuIHR3byBiaW9sb2dpY2FsIGNvbmRpdGlvbnMgaW4gYW4gaW50ZWdyYXRlZCBkYXRhLiBUaGlzIGludGVncmF0ZWQgZGF0YSBzZXQgaXMgZ2VuZXJhdGVkIGJ5IGNvbWJpbmluZyAxMCBtaWNyb2FycmF5IHN0dWRpZXMgb24gY29udHJvbCBhbmQgVEdGYi10cmVhdGVkIHNhbXBsZXMgKGZvciBtb3JlIGluZm9ybWF0aW9uLCBzZWUgaGVyZSBodHRwOi8vbWNyLmFhY3Jqb3VybmFscy5vcmcvY29udGVudC8xNS81LzYxOSkuXCAKCkZpcnN0LCB3ZSBhc3Nlc3MgdGhlIHByZXNlbmNlIG9mIHVud2FudGVkIHZhcmlhdGlvbiBpbiB0aGUgaW50ZWdyYXRlZCBkYXRhIHdoaWNoIGNvbWJpbmVzIGRpZmZlcmVudHMgc3R1ZGllcyBhbmQgcGxhdGZvcm1zLiBTZWNvbmQsIHdlIHNob3cgaG93IHRvIHVzZSB0d28gUlVWIG1ldGhvZHM6IFJVVmludiBhbmQgUlVWNCB0byByZW1vdmUgdW53YW50ZWQgdmFyaWF0aW9uIGFuZCBkZXRlY3QgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIGNvbXBhcmluZyBjb250cm9sIHNhbXBsZXMgdG8gVEdGYi10cmVhdGVkIHNhbXBsZXMuIFRoaXJkLCB3ZSBhc3Nlc3Mgd2hldGhlciBSVVYgbWV0aG9kcyBhcmUgdXNlZnVsIGFuZCBjb21wYXJlIHRoZSByZXN1bHRzIG9idGFpbmVkIGJ5IGVhY2ggbWV0aG9kLgpgYGB7ciBsb2FkLWxpYnN9CmxpYnJhcnkocnV2KSAgICAgICAgICAgICMjIGZvciBhcHBseWluZyBSVVYgbWV0aG9kcwpsaWJyYXJ5KGxpbW1hKSAgICAgICAgICAjIyBmb3IgdmVubkRpYWdyYW0oKQpsaWJyYXJ5KGdncGxvdDIpICAgICAgICAjIyBmb3IgZGF0YSB2aXN1YWxpc2F0aW9uCmBgYAoKVGhlIGludGVncmF0ZWQgZGF0YSBpbnRyb2R1Y2VkIGFib3ZlIGhhdmUgYmVlbiBzcGxpdCBpbnRvIHR3byBkYXRhIHNldHM6IHNhbXBsZXMgQSBhbmQgc2FtcGxlcyBCLCBlYWNoIGNvbnRhaW5pbmcgZGlmZmVyZW50IHN0dWRpZXMsIHBsYXRmb3JtcyBhbmQgdGlzc3Vlcy4gV2Ugd2lsbCBleHBsb3JlIGFuZCBub3JtYWxpc2UgdGhlc2UgdHdvIGRhdGEgc2V0cyBzZXBhcmF0ZWx5IGluIG9yZGVyIHRvIGNvbXBhcmUgdGhlIHJlc3VsdHMgb2J0YWluZWQgYnkgdGhlIHR3byBub3JtYWxpc2F0aW9uIG1ldGhvZHMgKFJVVjQgYW5kIFJVVmludikuCgpSZWFkIGluIHRoZSB0d28gaW50ZWdyYXRlZCBkYXRhc2V0cy4KYGBge3IgbG9hZC1kYXRhfQpzYW1wbGVzQTwtIHJlYWQudGFibGUoImV4cHJfMTBkYXRhX3NhbXBsZUEudHh0IiwgaGVhZGVyID0gVCwgc2VwID0gIlx0IikKc2FtcGxlc0I8LSByZWFkLnRhYmxlKCJleHByXzEwZGF0YV9zYW1wbGVCLnR4dCIsIGhlYWRlciA9IFQsIHNlcCA9ICJcdCIpCmBgYAoKTG9vayBhdCB0aGUgZGF0YSBpbiBlYWNoIHNhbXBsZXMgQSBhbmQgQiwgdGhlbiBtYWtlIGEgbWF0cml4IGZvciBlYWNoIHRoZXNlIGRhdGEgd2hlcmUgdGhlIHJvdyBuYW1lcyBhcmUgZ2VuZSBJRHMuCmBgYHtyIGV4cGxvcmUtZGF0YX0KCmhlYWQoc2FtcGxlc0EsMykKaGVhZChzYW1wbGVzQiwzKQptQTwtc2FtcGxlc0FbLDI6ZGltKHNhbXBsZXNBKVsyXV0KbUI8LXNhbXBsZXNCWywyOmRpbShzYW1wbGVzQilbMl1dCnJvdy5uYW1lcyhtQSk8LSBzYW1wbGVzQVssMV0Kcm93Lm5hbWVzKG1CKTwtIHNhbXBsZXNCWywxXQptQTwtIGFzLm1hdHJpeChtQSkKbUI8LSBhcy5tYXRyaXgobUIpCmBgYAoKTG9vayBhdCB0aGUgaW5mb3JtYXRpb24gcmVsYXRlZCB0byBlYWNoIHNhbXBsZSBpbmNsdWRpbmcgdGhlIG5hbWUgb2YgdGhlIHN0dWRpZXMsIHR5cGVzIG9mIHBsYXRmb3JtLCB0cmVhdG1lbnQsIGFuZCB0aXNzdWU6CmBgYHtyIGxvYWQtaW5mby1zdHVkeX0KaW5mb19zYW1wbGVzQTwtIHJlYWQudGFibGUoImluZm9fMTBkYXRhX3NhbXBsZUEudHh0Iiwgc2VwPSJcdCIsIGhlYWRlcj1UKQppbmZvX3NhbXBsZXNBCmluZm9fc2FtcGxlc0I8LSByZWFkLnRhYmxlKCJpbmZvXzEwZGF0YV9zYW1wbGVCLnR4dCIsIHNlcD0iXHQiLCBoZWFkZXI9VCkKaW5mb19zYW1wbGVzQgpgYGAKCiMgQXNzZXNzbWVudCBvZiB1bndhbnRlZCB2YXJpYXRpb24gaW4gdGhlIGRhdGEKSGVyZSB3ZSBwZXJmb3JtIHNvbWUgZXhwbG9yYXRvcnkgYW5hbHlzaXMgb24gdGhlIGludGVncmF0ZWQgZGF0YSB0byBhc3Nlc3MgdGhlIHByZXNlbmNlIG9mIHVud2FudGVkIHZhcmlhdGlvbiBpbiBlYWNoIGRhdGFzZXQuCgojIyBSTEUgcGxvdApXZSBzdGFydCBieSBsb29raW5nIGF0IHRoZSBSTEUgcGxvdHMgaW4gc2FtcGxlcyBBIGRhdGEsIGNvbG91cmVkIGJ5IHN0dWR5LCBwbGF0Zm9ybSBhbmQgdGlzc3VlOgpgYGB7ciBybGVwbG90cy1zYW1wbGVzQX0KIyMgVHJhbnNwb3NlIHRoZSBleHByZXNzaW9uIG1hdHJpeCBzbyB0aGF0IHdlIGhhdmUgZ2VuZXMgaW4gY29sdW1ucyBhbmQgc2FtcGxlcyBpbiByb3dzCllBIDwtIHQobUEpCiMjIFBsb3QgUkxFIGNvbG91cmVkIGJ5IHN0dWR5CnJ1dl9ybGUoWUEsIGluZm9fc2FtcGxlc0Ekc3R1ZHksIHlsaW0gPSBjKC00LDQpKQojIyBQbG90IFJMRSBjb2xvdXJlZCBieSBwbGF0Zm9ybQpydXZfcmxlKFlBLCBpbmZvX3NhbXBsZXNBJHBsYXRmb3JtLCB5bGltID0gYygtNCw0KSkKIyMgUGxvdCBSTEUgY29sb3VyZWQgYnkgcGxhdGZvcm0KcnV2X3JsZShZQSwgaW5mb19zYW1wbGVzQSR0aXNzdWUsIHlsaW0gPSBjKC00LDQpKQpgYGAKClNpbWlsYXJseSwgd2UgbG9vayBhdCB0aGUgUkxFIHBsb3RzIGluIHNhbXBsZSBCIGRhdGEgY29sb3VyZWQgYnkgc3R1ZHksIHBsYXRmb3JtIGFuZCB0aXNzdWU6CmBgYHtyIHJsZXBsb3RzLXNhbXBsZXNCfQpZQiA8LSB0KG1CKQojIyBQbG90IFJMRSBjb2xvdXJlZCBieSBzdHVkeQpydXZfcmxlKFlCLCBpbmZvX3NhbXBsZXNCJHN0dWR5LCB5bGltID0gYygtNCw0KSkKIyMgUGxvdCBSTEUgY29sb3VyZWQgYnkgcGxhdGZvcm0KcnV2X3JsZShZQiwgaW5mb19zYW1wbGVzQiRwbGF0Zm9ybSwgeWxpbSA9IGMoLTQsNCkpCiMjIFBsb3QgUkxFIGNvbG91cmVkIGJ5IHRpc3N1ZQpydXZfcmxlKFlCLCBpbmZvX3NhbXBsZXNCJHRpc3N1ZSwgeWxpbSA9IGMoLTQsNCkpCmBgYAoKIyMgUENBIHBsb3QKSW4gdHJhbnNjcmlwdG9taWNzIGFwcGxpY2F0aW9ucywgb25lIG9mIHRoZSBtb3N0IHV0aWxpemVkIGV4cGxvcmF0b3J5IHBsb3RzIGlzIHRoZSBtdWx0aS1kaW1lbnNpb25hbCBzY2FsaW5nIChNRFMpIHBsb3Qgb3IgYSBwcmluY2lwYWwgY29tcG9uZW50IGFuYWx5c2lzIChQQ0EpIHBsb3QuIFRvIGFzc2VzcyB0aGUgcHJlc2VuY2Ugb2YgdW53YW50ZWQgdmFyaWF0aW9uIGluIGVhY2ggc2FtcGxlLCB3ZSB1c2UgUENBIHBsb3RzIHRvIHNob3cgc2ltaWxhcml0aWVzIGJldHdlZW4gc2FtcGxlcyBtZWFzdXJlZCBpbiBhbiB1bnN1cGVydmlzZWQgd2F5LiBJZGVhbGx5LCBzYW1wbGVzIHNob3VsZCBjbHVzdGVyIHRvZ2V0aGVyIGFjY29yZGluZyB0byB0aGUgdHJlYXRtZW50IChpLmUuIHRoZSBiaW9sb2dpY2FsIGZhY3RvciBvZiBpbnRlcmVzdCkuIEhlcmUsIHdlIHNlZSB0aGF0IHNhbXBsZXMgYXJlIHJhdGhlciBjbHVzdGVyZWQgYnkgc3R1ZGllcyAoaS5lLiB1bndhbnRlZCB2YXJpYXRpb24pIGluIGJvdGggc2FtcGxlcyBBIGFuZCBCIGRhdGEuXApJbiB0aGUgY3VycmVudCBleGFtcGxlLCBpdCdzIGltcG9ydGFudCB0byBub3RlIHRoYXQgaW4gc29tZSBjYXNlcywgZGlmZmVyZW50IHN0dWRpZXMgYXJlIGNvbmZvdW5kZWQgd2l0aCBkaWZmZXJlbnQgcGxhdGZvcm1zIGFuZCB0aXNzdWVzLCBhbmQgdGhlcmVmb3JlIHRoZXJlIGlzIG5vIHdheSB0byBpZGVudGlmeSBob3cgbXVjaCBvZiB0aGUgdW53YW50ZWQgdmFyaWF0aW9uIGNvbWUgZnJvbSBlYWNoIG9mIHRoZXNlIGZhY3RvcnMuIFN1Y2ggc2l0dWF0aW9ucyBtdXN0IGJlIGF2b2lkZWQgd2hlbiBkZXNpZ25pbmcgYW4gZXhwZXJpbWVudCBhbmQgZm9yIHRoZSBwdXJwb3NlIG9mIHRoaXMgdHV0b3JpYWwsIHdlIG9ubHkgY29uc2lkZXIgInN0dWR5IiBhcyB0aGUgc291cmNlIG9mIHVud2FudGVkIHZhcmlhdGlvbi5cCgpgYGB7ciBtZHMtcGxvdC1zYW1wbGVBfQpnZ19hZGRpdGlvbnMgPC0gbGlzdChhZXMoY29sb3IgPSBpbmZvX3NhbXBsZXNBJHN0dWR5LCAKICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gaW5mb19zYW1wbGVzQSR0cmVhdG1lbnQsIAogICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDUsIGFscGhhID0gLjcpLAogICAgICAgICAgICAgICAgICAgICBsYWJzKGNvbG9yID0gIlN0dWR5Iiwgc2hhcGU9IlRyZWF0bWVudCIpLAogICAgICAgICAgICAgICAgICAgICBzY2FsZV9zaXplX2lkZW50aXR5KGd1aWRlID0gIm5vbmUiKSwKICAgICAgICAgICAgICAgICAgICAgc2NhbGVfYWxwaGEoZ3VpZGUgPSAibm9uZSIpLAogICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSksCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA0KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA0KSkpKQpvcHRpb25zKHJlcHIucGxvdC53aWR0aCA9IDgsIHJlcHIucGxvdC5oZWlnaHQgPSA2KQpydXZfc3ZkcGxvdChZQSkgKyBnZ19hZGRpdGlvbnMgCmBgYAoKYGBge3IgbWRzLXBsb3Qtc2FtcGxlQn0KZ2dfYWRkaXRpb25zIDwtIGxpc3QoYWVzKGNvbG9yID0gaW5mb19zYW1wbGVzQiRzdHVkeSwKICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gaW5mb19zYW1wbGVzQiR0cmVhdG1lbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gNSwgYWxwaGEgPSAuNyksCiAgICAgICAgICAgICAgICAgICAgIGxhYnMoY29sb3IgPSAiU3R1ZHkiLHNoYXBlID0gIlRyZWF0bWVudCIpLAogICAgICAgICAgICAgICAgICAgICBzY2FsZV9zaXplX2lkZW50aXR5KGd1aWRlID0gIm5vbmUiKSwKICAgICAgICAgICAgICAgICAgICAgc2NhbGVfYWxwaGEoZ3VpZGUgPSAibm9uZSIpLAogICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSksCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA0KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA0KSkpKQpvcHRpb25zKHJlcHIucGxvdC53aWR0aD04LCByZXByLnBsb3QuaGVpZ2h0PTYpCnJ1dl9zdmRwbG90KFlCKSArIGdnX2FkZGl0aW9ucyAjCmBgYAoKCiMgUmVtb3ZlIGJhdGNoIGVmZmVjdHMgdXNpbmcgUlVWIG1ldGhvZHMKVGhlcmUgYXJlIHNldmVyYWwgUlVWIG1ldGhvZHMgZm9yIHJlbW92aW5nIHVud2FudGVkIHZhcmlhdGlvbiBpbiBvcmRlciB0byBvYnRhaW4gREVHczsgdGhlc2UgaW5jbHVkZSBSVVYtMiwgUlVWLTQsIFJVVi1pbnYgYW5kIFJVVi1yaW52LiBJbiBnZW5lcmFsLCBSVVYgbWV0aG9kcyBhcmUgZGVwZW5kZW50IG9uIG5lZ2F0aXZlIGNvbnRyb2wgZ2VuZXMgKGdlbmVzIHdoaWNoIGFyZSBub3QgYXNzb2NpYXRlZCB3aXRoIHRoZSBiaW9sb2dpY2FsIGZhY3RvciBvZiBpbnRlcmVzdCkgYW5kIHJlcGxpY2F0ZSBzYW1wbGVzIChpZiBhcHBsaWNhYmxlKS4gUlVWLTIgcmVtb3ZlcyB1bndhbnRlZCB2YXJpYXRpb24gaW4gdHdvIHN0ZXBzLiBSVVYtNCBjYW1lIGFmdGVyIFJVVi0yIGFuZCBoYXMgZm91ciBzdGVwcy4gRm9yIFJVVi00IHdlIGNhbiBlc3RpbWF0ZSB0aGUgZGltZW5zaW9uIG9mIHVud2FudGVkIHZhcmlhdGlvbiAoaykgb3Igc2VsZWN0IGRpZmZlcmVudCB2YWx1ZXMgZm9yIGssIHdoaWxlIGZvciBSVVYtaW52IGFuZCBSVVYtcmludiB3ZSBkb24ndCBuZWVkIHRvIGVzdGltYXRlIGsgYXMgaXQgaXMgc2V0IHRvIGJlIHRoZSBtYXhpbXVtIHZhbHVlLiBJbiBnZW5lcmFsLCBSVVYtaW52IGFuZCBSVVYtcmludiBhcmUgYmV0dGVyIHRoYW4gUlVWLTQuIFJVVi1pbnYgaXMgcmVjb21tZW5kZWQgd2hlbiB3ZSBoYXZlIGxhcmdlIG51bWJlciBvZiBjb250cm9sIGdlbmVzICh+MTAwMCksIHdoaWxlIFJVVi1yaW52IGlzIG1vcmUgYXBwcm9wcmlhdGUgd2l0aCBzbWFsbCBudW1iZXIgb2YgY29udHJvbCBnZW5lcyAofjYwKS5cCgpTZWxlY3Rpb24gb2YgbmVnYXRpdmUgY29udHJvbCBnZW5lcyBpcyB2ZXJ5IGltcG9ydGFudC4gRXhhbXBsZXMgb2YgbmVnYXRpdmUgY29udHJvbCBnZW5lcyBhcmUgdGhlIHNwaWtlLWluIGNvbnRyb2xzIG9yIHRoZSBob3VzZWtlZXBpbmcgKEhLKSBnZW5lcy4gSXQgaXMgYWxzbyBwb3NzaWJsZSB0byBkZWZpbmUgZW1waXJpY2FsIG5lZ2F0aXZlIGNvbnRyb2wgZ2VuZXMgdXNpbmcgYW4gaXRlcmF0aXZlIGFwcHJvYWNoLiBIb3dldmVyLCBpdCBpcyBvbmx5IHJlY29tZW5kZWQgaWYgKGkpIHRoZSBpbml0aWFsIG5lZ2F0aXZlIGNvbnRyb2wgZ2VuZXMgYXJlIG5vdCB2ZXJ5IGdvb2Qgb3IgdGhlcmUgYXJlIG9ubHkgYSBmZXcgb2YgdGhlbTsgKGlpKSB0aGUgYmV0YSBzZWVtcyB0byBiZSB2ZXJ5IHNwYXJzZS4gVGhlcmVmb3JlLCB0aGUgdXNlciBuZWVkcyB0byBnZW5lcmF0ZSBkaWFnbm9zdGljIHBsb3RzIHRvIGFzc2VzcyB0aGUgcGVyZm9ybWFuY2Ugb2YgdGhlIGluaXRpYWwgYW5hbHlzaXMsIGFuZCBvbmx5IGlmIG5lZWRlZCwgdXNlIGFuIGl0ZXJhdGl2ZSBhcHByb2FjaCB0byBkZWZpbmUgYmV0dGVyIGNvbnRyb2wgZ2VuZXMuCgojIyBSVVZpbnYKCkhlcmUsIHdlIGZpcnN0IGZvY3VzIG9uIFJVVi1pbnYsIHdoaWNoIGlzIHBlcmZvcm1lZCBieSAqKlJVVmludigpKiogZnVuY3Rpb24uIFRoaXMgZnVuY3Rpb24gdGFrZSBleHByZXNzaW9uIG1hdHJpeCAoWSksIGJpb2xvZ2ljYWwgZmFjdG9yIG9mIGludGVyZXN0IChYKSwgYW5kIGEgdmVjdG9yIGZvciBpbmRpY2VzIG9mIG5lZ2F0aXZlIGNvbnRyb2wgZ2VuZXMgKGN0bCkuCgojIyMgQXBwbHkgUlVWaW52IHVzaW5nIGhvdXNlLWtlZXBpbmcgZ2VuZXMKV2UgYmVnaW4gd2l0aCB0aGUgbGlzdCBvZiBob3VzZWtlZXBpbmcgKEhLKSBnZW5lcyBhcyBvdXIgbmVnYXRpdmUgY29udHJvbHMuCmBgYHtyfQpIS2dlbmVzIDwtIHJlYWQudGFibGUoIkhvdXNlS2VlcGluZ19nZW5lc19JRHMudHh0IiwgaGVhZGVyPVQsIHNlcD0iXHQiKQpoayA8LSBIS2dlbmVzJEdlbmVJRApjdHJsIDwtIGNvbG5hbWVzKFlBKSAlaW4lIGhrCmBgYAoKV2UgcnVuIFJVVmludiB1c2luZyBISyBnZW5lcyBvbiBzYW1wbGVzIEEgZGF0YS4KYGBge3IgaW5pdGlhbC1hbmFseXNpcy1oay1nZW5lcy1zYW1wbGVzQX0KIyMgVGFrZSB0cmVhdG1lbnQgYXMgdGhlIGJpb2xvZ2ljYWwgZmFjdG9yIG9mIGludGVyZXN0Cmdyb3Vwc19BIDwtIGZhY3RvcihpbmZvX3NhbXBsZXNBJHRyZWF0bWVudCkgCmdBIDwtIGNiaW5kKGFzLm51bWVyaWMoZ3JvdXBzX0EpKSAgICMjIDEgY29udHJvbCwgMjogVEdGYgoKCiMjIEFwcGx5IFJVVi1pbnYgdXNpbmcgdGhlIGhvdXNla2VlcGluZyBnZW5lcyBhcyBuZWdhdGl2ZSBjb250cm9scyAKZml0X3J1dmluX2hrX3NhbXBsZXNBIDwtIFJVVmludihZQSwgZ0EsIGN0cmwpCmZpdF9ydXZpbl9oa19zYW1wbGVzQS5zdW1tYXJ5IDwtIHJ1dl9zdW1tYXJ5KFlBLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZml0X3J1dmluX2hrX3NhbXBsZXNBLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mb19zYW1wbGVzQSkKaGVhZChmaXRfcnV2aW5faGtfc2FtcGxlc0Euc3VtbWFyeSRDKQpgYGAKCkNoZWNrIGlmIEhLIGdlbmVzIGFzIG5lZ2F0aXZlIGNvbnRyb2wgZ2VuZXMgaW4gdGhlIGluaXRpYWwgYW5hbHlzaXMgd2VyZSB1c2VmdWwuCmBgYHtyIGRpYWdub3N0aWMtcGxvdHMtaW50aWFsLWFuYWx5c2lzLXNhbXBsZXNBfQojIyBMb29rIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgcC12YWx1ZXMKcnV2X2hpc3QoZml0X3J1dmluX2hrX3NhbXBsZXNBLnN1bW1hcnkpCgojIyBMb29rIGF0IHRoZSB2b2xjYW5vIHBsb3QKZ2VuZWNvbG9yaW5nIDwtIGxpc3QoYWVzKGNvbG9yID0gZml0LmN0bCksCiAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIkdlbmUgQ2F0ZWdvcnkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYWxwaGEoYygiUmVkIiwgImJsYWNrIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYyggMC4xLCAwLjI1KSkpKQpydXZfdm9sY2FubyhmaXRfcnV2aW5faGtfc2FtcGxlc0Euc3VtbWFyeSkgKyBnZW5lY29sb3JpbmcKCiMjIExvb2sgYXQgRUNERiBvZiBwLXZhbHVlcwpydXZfZWNkZihmaXRfcnV2aW5faGtfc2FtcGxlc0Euc3VtbWFyeSkgKyBnZW5lY29sb3JpbmcKYGBgCgpTaW1pbGFybHksIHdlIHJ1biBSVVZpbnYgdXNpbmcgSEsgZ2VuZXMgb24gc2FtcGxlcyBCIGRhdGEuCmBgYHtyIGluaXRpYWwtYW5hbHlzaXMtaGstZ2VuZXMtc2FtcGxlc0J9CiMjIFRha2UgdHJlYXRtZW50IGFzIHRoZSBiaW9sb2dpY2FsIGZhY3RvciBvZiBpbnRlcmVzdApncm91cHNfQiA8LSBmYWN0b3IoaW5mb19zYW1wbGVzQiR0cmVhdG1lbnQpIApnQiA8LSBjYmluZChhcy5udW1lcmljKGdyb3Vwc19CKSkgICAjIyAxIGNvbnRyb2wsIDI6IFRHRmIKCiMjIEFwcGx5IFJVVi1pbnYgdXNpbmcgdGhlIGhvdXNla2VlcGluZyBnZW5lcyBhcyBuZWdhdGl2ZSBjb250cm9scyAKZml0X3J1dmluX2hrX3NhbXBsZXNCIDwtIFJVVmludihZQiwgZ0IsIGN0cmwpCmZpdF9ydXZpbl9oa19zYW1wbGVzQi5zdW1tYXJ5IDwtIHJ1dl9zdW1tYXJ5KFlCLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZml0X3J1dmluX2hrX3NhbXBsZXNCLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mb19zYW1wbGVzQikKCmhlYWQoZml0X3J1dmluX2hrX3NhbXBsZXNCLnN1bW1hcnkkQykKYGBgCgpDaGVjayBpZiBISyBnZW5lcyBhcyBuZWdhdGl2ZSBjb250cm9sIGdlbmVzIGluIHRoZSBpbml0aWFsIGFuYWx5c2lzIHdlcmUgdXNlZnVsLgpgYGB7ciBkaWFnbm9zdGljLXBsb3RzLWludGlhbC1hbmFseXNpcy1zYW1wbGVzQn0KIyMgTG9vayBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHAtdmFsdWVzCnJ1dl9oaXN0KGZpdF9ydXZpbl9oa19zYW1wbGVzQi5zdW1tYXJ5KQoKIyMgTG9vayBhdCB0aGUgdm9sY2FubyBwbG90CmdlbmVjb2xvcmluZyA8LSBsaXN0KGFlcyhjb2xvciA9IGZpdC5jdGwpLAogICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJHZW5lIENhdGVnb3J5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGFscGhhKGMoIlJlZCIsICJibGFjayIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIDAuMSwgMC4yNSkpKSkKcnV2X3ZvbGNhbm8oZml0X3J1dmluX2hrX3NhbXBsZXNCLnN1bW1hcnkpICsgZ2VuZWNvbG9yaW5nCgojIyBMb29rIGF0IEVDREYgb2YgcC12YWx1ZXMKcnV2X2VjZGYoZml0X3J1dmluX2hrX3NhbXBsZXNCLnN1bW1hcnkpICsgZ2VuZWNvbG9yaW5nCmBgYAoKIyMjIEFwcGx5IFJVVmludiB1c2luZyBlbXBpcmljYWwgY29udHJvbCBnZW5lcwpBY2NvcmRpbmcgdG8gdGhlIGFib3ZlIHJlc3VsdHMsIHNvbWUgb2YgdGhlIEhLIGdlbmVzIHNlZW0gdG8gYmUgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkLiBJbiB0aGVzZSBjYXNlcywgaXQgaXMgb2Z0ZW4gcmVjb21lbmRlZCB0byB1c2UgUlVWNCBhcyB3ZSBjYW4gbWFudWFsbHkgY2hhbmdlIHRoZSBrLCB3aGVyZSBzbWFsbGVyIGsgbWF5IHJldGFpbiBtb3JlIG9mIHRoZSBiaW9sb2dpY2FsIHNpZ25hbCBhbmQgbGFyZ2VyIGsgbWF5IG92ZXJhZGp1c3QgdGhlIGRhdGEuIEZvciBub3csIHdlIGNvbnRpbnVlIHdpdGggUlVWaW52IHRvIHNob3cgaG93IHRvIGRlZmluZSAqKmVtcGlyaWNhbCBuZWdhdGl2ZSBjb250cm9sIGdlbmVzKiosIGJ5IHNlbGVjdGluZyB0aG9zZSBnZW5lcyB0aGF0IHdlcmUgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgaW4gdGhlIHJlc3VsdHMgb2YgdGVoIGluaXRpdGFsIGFuYWx5c2lzLiBOZXh0LCB3ZSBzaG93IHRoZSB1c2Ugb2YgUlVWNCBvbiB0aGVzZSBkYXRhLiAKCmBgYHtyIHJ1di1pbnYtc2FtcGxlc0F9CiMjIFNlbGVjdGluZyBlbXBpcmljYWwgbmVnYXRpdmUgY29udHJvbHMgZ2VuZXMKY0dlbmVzX3NhbXBsZXNBIDwtIHJvdy5uYW1lcyhmaXRfcnV2aW5faGtfc2FtcGxlc0Euc3VtbWFyeSRDKVtmaXRfcnV2aW5faGtfc2FtcGxlc0Euc3VtbWFyeSRDJEYucC5CSCA+IDAuMDVdICAKbGVuZ3RoKGNHZW5lc19zYW1wbGVzQSkKCmVtcEN0cmxfcnV2aW52X3NhbXBsZXNBIDwtIGNvbG5hbWVzKFlBKSAlaW4lIGNHZW5lc19zYW1wbGVzQQoKR2VuZV9DYXRlZ29yeSA8LSBlbXBDdHJsX3J1dmludl9zYW1wbGVzQQpHZW5lX0NhdGVnb3J5W2VtcEN0cmxfcnV2aW52X3NhbXBsZXNBID09IFRdIDwtICJFbXBDdGwiCkdlbmVfQ2F0ZWdvcnlbZW1wQ3RybF9ydXZpbnZfc2FtcGxlc0EgPT0gRl0gPC0gIk5vbl9FbXBDdGwiCkVtcF9DdF9HZW5lc19zYW1wbGVzQSA8LSBkYXRhLmZyYW1lKGdlbmVpZHMgPSBjb2xuYW1lcyhZQSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVtcEN0X1JVViA9IGVtcEN0cmxfcnV2aW52X3NhbXBsZXNBLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDYXRlZyA9IEdlbmVfQ2F0ZWdvcnkpCmhlYWQoRW1wX0N0X0dlbmVzX3NhbXBsZXNBKQoKYGBgCiBBbmQgc2ltaWxhcmx5IGZvciBzYW1wbGUgQjoKYGBge3IgcnV2LWludi1zYW1wbGVzQn0KIyMgU2VsZWN0IGVtcGlyaWNhbCBuZWdhdGl2ZSBjb250cm9scyBnZW5lcwpjR2VuZXNfc2FtcGxlc0IgPC0gcm93Lm5hbWVzKGZpdF9ydXZpbl9oa19zYW1wbGVzQi5zdW1tYXJ5JEMpW2ZpdF9ydXZpbl9oa19zYW1wbGVzQi5zdW1tYXJ5JEMkRi5wLkJIID4gMC4wNV0KbGVuZ3RoKGNHZW5lc19zYW1wbGVzQikKCmVtcEN0cmxfcnV2aW52X3NhbXBsZXNCPC0gY29sbmFtZXMoWUIpICVpbiUgY0dlbmVzX3NhbXBsZXNCCgpHZW5lX0NhdGVnb3J5IDwtIGVtcEN0cmxfcnV2aW52X3NhbXBsZXNCCkdlbmVfQ2F0ZWdvcnlbZW1wQ3RybF9ydXZpbnZfc2FtcGxlc0I9PVRdPSJFbXBDdGwiCkdlbmVfQ2F0ZWdvcnlbZW1wQ3RybF9ydXZpbnZfc2FtcGxlc0I9PUZdPSJOb25fRW1wQ3RsIgpFbXBfQ3RfR2VuZXNfc2FtcGxlc0IgPC0gZGF0YS5mcmFtZShnZW5laWRzID0gY29sbmFtZXMoWUIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbXBDdF9SVVYgPSBlbXBDdHJsX3J1dmludl9zYW1wbGVzQiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ2F0ZWcgPSBHZW5lX0NhdGVnb3J5KQoKaGVhZChFbXBfQ3RfR2VuZXNfc2FtcGxlc0IpCgpgYGAKCk5vdyB3ZSB1c2UgdGhvc2UgZW1waXJpY2FsIGNvbnRyb2wgZ2VuZXMgdG8gYXBwbHkgUlVWaW52IGluIHNhbXBsZXMgQSBhbmQgQiBkYXRhIHNldHMuCmBgYHtyIGVtcC1ydXZpbnZ9CiMjLS0tLSBJbiBzYW1wbGVzIEEgZGF0YToKZml0X3J1dmluX2VtcF9zYW1wbGVzQSA8LSBSVVZpbnYoWSA9IFlBLCBYID0gZ0EsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdGwgPSBFbXBfQ3RfR2VuZXNfc2FtcGxlc0EkZW1wQ3RfUlVWLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBaID0gMSwgZnVsbFcwID0gTlVMTCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhbWJkYSA9IE5VTEwsIGl0ZXJOID0gMTAwMDAwKQoKZml0X3J1dmluX2VtcF9zYW1wbGVzQS5zdW1tYXJ5IDwtIHJ1dl9zdW1tYXJ5KFlBLCBmaXRfcnV2aW5fZW1wX3NhbXBsZXNBLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mb19zYW1wbGVzQSwgICAgICAgICAgICAgICMjIHJvdyBpbmZvCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVtcF9DdF9HZW5lc19zYW1wbGVzQSkgICAgICAjIyBjb2wgaW5mbwoKIyMtLS0tIEluIHNhbXBsZXMgQiBkYXRhOiAKZml0X3J1dmluX2VtcF9zYW1wbGVzQiA8LSBSVVZpbnYoWSA9IFlCLCBYID0gZ0IsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN0bCA9IEVtcF9DdF9HZW5lc19zYW1wbGVzQiRlbXBDdF9SVVYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFogPSAxLCBmdWxsVzAgPSBOVUxMLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYW1iZGEgPSBOVUxMLCBpdGVyTiA9IDEwMDAwMCkKCmZpdF9ydXZpbl9lbXBfc2FtcGxlc0Iuc3VtbWFyeSA8LSBydXZfc3VtbWFyeShZQiwgZml0X3J1dmluX2VtcF9zYW1wbGVzQiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZm9fc2FtcGxlc0IsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbXBfQ3RfR2VuZXNfc2FtcGxlc0IpCmBgYAoKSGVyZSwgd2UgbG9vayBhdCB0aGUgc3RhdGlzdGljcyBvYnRhaW5lZCBmb3Igc2FtcGxlcyBBIGRhdGEuCmBgYHtyIGVtcC1ydXZpbnYtc2FtcGxlQS1yZXN1bHRzfQojIyBMb29rIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgcC12YWx1ZXMKcnV2X2hpc3QoZml0X3J1dmluX2VtcF9zYW1wbGVzQS5zdW1tYXJ5KQoKIyMgTG9vayBhdCB0aGUgVm9sY2FubyBwbG90CmdlbmVjb2xvcmluZyA8LSBsaXN0KGFlcyhjb2xvciA9IENhdGVnKSwgCiAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiR2VuZSBDYXRlZ29yeSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGFscGhhKGMoIkJsYWNrIiwgInJlZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCAwLjEsIDAuMjUpKSkpCnJ1dl92b2xjYW5vKGZpdF9ydXZpbl9lbXBfc2FtcGxlc0Euc3VtbWFyeSkgKyBnZW5lY29sb3JpbmcKCiMjIExvb2sgYXQgRUNERiBvZiBwLXZhbHVlcwpydXZfZWNkZihmaXRfcnV2aW5fZW1wX3NhbXBsZXNBLnN1bW1hcnkpICsgZ2VuZWNvbG9yaW5nCmBgYAoKCk5vdyB3ZSBsb29rIGF0IHRoZSBzdGF0aXN0aWNzIG9idGFpbmVkIGZvciBzYW1wbGVzIEIgZGF0YS4KYGBge3IgZW1wLXJ1dmludi1zYW1wbGVCLXJlc3VsdHN9CiMjIExvb2sgYXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiBwLXZhbHVlcwpydXZfaGlzdChmaXRfcnV2aW5fZW1wX3NhbXBsZXNCLnN1bW1hcnkpCgojIyBMb29rIGF0IHRoZSB2b2xjYW5vIHBsb3QKZ2VuZWNvbG9yaW5nIDwtIGxpc3QoYWVzKGNvbG9yID0gQ2F0ZWcpLAogICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIkdlbmUgQ2F0ZWdvcnkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBhbHBoYShjKCJCbGFjayIsIlJlZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYyggMC4yLCAwLjIpKSkpCnJ1dl92b2xjYW5vKGZpdF9ydXZpbl9lbXBfc2FtcGxlc0Iuc3VtbWFyeSkgKyBnZW5lY29sb3JpbmcKCiMjIExvb2sgYXQgRUNERiBvZiBwLXZhbHVlcwpydXZfZWNkZihmaXRfcnV2aW5fZW1wX3NhbXBsZXNCLnN1bW1hcnkpICsgZ2VuZWNvbG9yaW5nCmBgYAoKIyMgUlVWNApSVVY0IGNhbiBiZSBydW4gd2l0aCBkaWZmZXJlbnQgdmFsdWVzIG9mIGsgaW4gYW4gYXR0ZW1wdCB0byBmaW5kIHRoZSBvcHRpbWFsIHZhbHVlLiBOb3RlIHRoYXQgYWx0aG91Z2ggdGhlcmUgaXMgYSBmdW5jdGlvbiB0byBlc3RpbWF0ZSBrLCBjYWxsZWQgKipnZXRLKCkqKiwgdGhpcyBtYXkgbm90IGdpdmUgdGhlIG9wdGltYWwgdmFsdWUgZm9yIGsgYW5kIGlzIG9mdGVuIHJlY29tZW5kZWQgdG8gYmUgdXNlZCB3aGVuIHRoZXJlIGlzIG5vIG90aGVyIGNob2ljZSBidXQgdG8gYXV0b21hdGUgZmluZGluZyBLIChlLmcuIGluIHNpbXVsYXRpb25zKS4gCgojIyMgQXBwbHkgUlVWNCB1c2luZyBlbXBpcmljYWwgY29udHJvbCBnZW5lcwpSdW4gUlVWNCB1c2luZyBkaWZmZXJlbnQgdmFsdWVzIG9mIGsgYW5kIGVtcHJpY2FsIGNvbnRyb2xzLgpgYGAge3IgcnV2NC1FbXBpcmljYWwtZGlmZmVyZW50S3N9CgojIyBJbnN0ZWFkIG9mIGVzdGltYXRpbmcgayAoY29tbWVudGVkIGJlbG93KSwgd2UgbG9vayBhdCBkaWZmZXJlbnQgdmFsdWVzIGZvciBrLgojIGVzdGltYXRlSzwtIGdldEsoWUEsIFg9Z0EsCiMgICAgICAgICAgICAgICAgICBjdGw9RW1wX0N0X0dlbmVzX3NhbXBsZXNBJGVtcEN0X1JVViwKIyAgICAgICAgICAgICAgICAgIFogPSAxLCBldGEgPSBOVUxMLCBmdWxsVzAgPSBOVUxMLCBjdXRvZmYgPSBOVUxMLAojICAgICAgICAgICAgICAgICAgbWV0aG9kPSJzZWxlY3QiLCBsPTEsIGlucHV0Y2hlY2sgPSBUUlVFKQojIGtBIDwtIGVzdGltYXRlSyRrICAgIyMgaXQgd2lsbCBiZSBrID0gMTEKCiMgZXN0aW1hdGVLPC0gZ2V0SyhZQiwgWD1nQiwKIyAgICAgICAgICAgICAgICAgIGN0bD1FbXBfQ3RfR2VuZXNfc2FtcGxlc0IkZW1wQ3RfUlVWLAojICAgICAgICAgICAgICAgICAgWiA9IDEsIGV0YSA9IE5VTEwsIGZ1bGxXMCA9IE5VTEwsIGN1dG9mZiA9IE5VTEwsCiMgICAgICAgICAgICAgICAgICBtZXRob2Q9InNlbGVjdCIsIGw9MSwgaW5wdXRjaGVjayA9IFRSVUUpCiMga0IgPC0gZXN0aW1hdGVLJGsgICAjIyBpdCB3aWxsIGJlIGsgPSA4CgprcyA8LSBjKDEsIDIsIDUsIDYsIDcsIDgsIDEwLCAxMSwgMTIsIDE1LCAxOCwgMjAsIDIyLCAyMywgMjQpCiMjIEZvciBrID4gMjQgSSBnb3QgRXJyb3I6CiMgTmFOcyBwcm9kdWNlZE5hTnMgcHJvZHVjZWRFcnJvciBpbiBzaWdtYXNocmluayhmaXQkc2lnbWEyLCBmaXQkZGYpIDogCiMgICBOQS9OYU4vSW5mIGluIGZvcmVpZ24gZnVuY3Rpb24gY2FsbCAoYXJnIDEpCgpiZXRhX2NvckFCIDwtIHZlY3RvcigpCgpmb3IgKEsgaW4ga3MpewogIGZpdF9ydXY0X2VtcF9zYW1wbGVBIDwtIFJVVjQoWUEsIFggPSBnQSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdGwgPSBFbXBfQ3RfR2VuZXNfc2FtcGxlc0EkZW1wQ3RfUlVWLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGsgPSBLLFogPSAxLCBldGEgPSBOVUxMLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bGxXMCA9IE5VTEwsIGlucHV0Y2hlY2sgPSBUUlVFKQogIAogIGZpdF9ydXY0X2VtcF9zYW1wbGVBLnN1bW1hcnkgPC0gcnV2X3N1bW1hcnkoWUEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaXRfcnV2NF9lbXBfc2FtcGxlQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZm9fc2FtcGxlc0EsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbXBfQ3RfR2VuZXNfc2FtcGxlc0EpCiAgCiAgZml0X3J1djRfZW1wX3NhbXBsZUIgPC0gUlVWNChZQiwgWCA9IGdCLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN0bCA9IEVtcF9DdF9HZW5lc19zYW1wbGVzQiRlbXBDdF9SVVYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgayA9IEssWiA9IDEsIGV0YSA9IE5VTEwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVsbFcwID0gTlVMTCwgaW5wdXRjaGVjayA9IFRSVUUpCiAgCiAgZml0X3J1djRfZW1wX3NhbXBsZUIuc3VtbWFyeSA8LSBydXZfc3VtbWFyeShZQiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpdF9ydXY0X2VtcF9zYW1wbGVCLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mb19zYW1wbGVzQiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVtcF9DdF9HZW5lc19zYW1wbGVzQikKICAKICBjdXJyZW50Q29yIDwtIGNvci50ZXN0KGZpdF9ydXY0X2VtcF9zYW1wbGVBJGJldGFoYXQsCiAgICAgICAgICAgICAgICAgICAgICAgIGZpdF9ydXY0X2VtcF9zYW1wbGVCJGJldGFoYXQpJGVzdGltYXRlCiAgCiAgYmV0YV9jb3JBQiA8LSBjKGJldGFfY29yQUIsIGN1cnJlbnRDb3IpCiAgCn0KbmFtZXMoYmV0YV9jb3JBQikgPC0ga3MKYmV0YV9jb3JBQiAjIyBLID0gMjMgc2VlbXMgYSBnb29kIGNob2ljZQpgYGAKCiMjIyBBcHBseSBSVVY0IHVzaW5nIGhvdXNlLWtlZXBpbmcgZ2VuZXMKYGBgIHtyIHJ1djQtSEstZGlmZmVyZW50S3N9CgojIyBJbnN0ZWFkIG9mIGVzdGltYXRpbmcgayAoY29tbWVudGVkIGJlbG93KSwgd2UgbG9vayBhdCBkaWZmZXJlbnQgdmFsdWVzIGZvciBrLgojIGVzdGltYXRlSzwtIGdldEsoWUEsIFggPSBnQSwKIyAgICAgICAgICAgICAgICAgIGN0bCA9IGN0cmwsCiMgICAgICAgICAgICAgICAgICBaID0gMSwgZXRhID0gTlVMTCwgZnVsbFcwID0gTlVMTCwgY3V0b2ZmID0gTlVMTCwKIyAgICAgICAgICAgICAgICAgIG1ldGhvZD0ic2VsZWN0IiwgbD0xLCBpbnB1dGNoZWNrID0gVFJVRSkKIyBrQSA8LSBlc3RpbWF0ZUskayAgICMjIGl0IHdpbGwgYmUgayA9IDcKIyAKIyBlc3RpbWF0ZUs8LSBnZXRLKFlCLCBYID0gZ0IsCiMgICAgICAgICAgICAgICAgICBjdGwgPSBjdHJsLAojICAgICAgICAgICAgICAgICAgWiA9IDEsIGV0YSA9IE5VTEwsIGZ1bGxXMCA9IE5VTEwsIGN1dG9mZiA9IE5VTEwsCiMgICAgICAgICAgICAgICAgICBtZXRob2Q9InNlbGVjdCIsIGw9MSwgaW5wdXRjaGVjayA9IFRSVUUpCiMga0IgPC0gZXN0aW1hdGVLJGsgICAjIyBpdCB3aWxsIGJlIGsgPSA2CgprcyA8LSBjKDEsIDIsIDUsIDYsIDcsIDgsIDEwLCAxMSwgMTIsIDE1LCAxOCwgMjAsIDIyLCAyMywgMjQpCiMjIEZvciBrID4gMjQgSSBnb3QgRXJyb3I6CiMgTmFOcyBwcm9kdWNlZE5hTnMgcHJvZHVjZWRFcnJvciBpbiBzaWdtYXNocmluayhmaXQkc2lnbWEyLCBmaXQkZGYpIDogCiMgICBOQS9OYU4vSW5mIGluIGZvcmVpZ24gZnVuY3Rpb24gY2FsbCAoYXJnIDEpCgpiZXRhX2NvckFCX0hLIDwtIHZlY3RvcigpCgpmb3IgKEsgaW4ga3MpewogIGZpdF9ydXY0X2hrX3NhbXBsZUEgPC0gUlVWNChZQSwgWCA9IGdBLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN0bCA9IGN0cmwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgayA9IEssWiA9IDEsIGV0YSA9IE5VTEwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVsbFcwID0gTlVMTCwgaW5wdXRjaGVjayA9IFRSVUUpCiAgCiAgZml0X3J1djRfaGtfc2FtcGxlQS5zdW1tYXJ5IDwtIHJ1dl9zdW1tYXJ5KFlBLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZml0X3J1djRfaGtfc2FtcGxlQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZm9fc2FtcGxlc0EpCiAgCiAgZml0X3J1djRfaGtfc2FtcGxlQiA8LSBSVVY0KFlCLCBYID0gZ0IsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY3RsID0gY3RybCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBrID0gSyxaID0gMSwgZXRhID0gTlVMTCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdWxsVzAgPSBOVUxMLCBpbnB1dGNoZWNrID0gVFJVRSkKICAKICBmaXRfcnV2NF9oa19zYW1wbGVCLnN1bW1hcnkgPC0gcnV2X3N1bW1hcnkoWUIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaXRfcnV2NF9oa19zYW1wbGVCLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mb19zYW1wbGVzQikKICAKICBjdXJyZW50Q29yIDwtIGNvci50ZXN0KGZpdF9ydXY0X2hrX3NhbXBsZUEkYmV0YWhhdCwKICAgICAgICAgICAgICAgICAgICAgICAgZml0X3J1djRfaGtfc2FtcGxlQiRiZXRhaGF0KSRlc3RpbWF0ZQogIAogIGJldGFfY29yQUJfSEsgPC0gYyhiZXRhX2NvckFCX0hLLCBjdXJyZW50Q29yKQogIAp9Cm5hbWVzKGJldGFfY29yQUJfSEspIDwtIGtzCmJldGFfY29yQUJfSEsgIyMgSyA9IDIzIHNlZW1zIGEgZ29vZCBjaG9pY2UKYGBgCgpBcyBrID0gMjMgcmVzdWx0cyBpbiB0aGUgaGlnaGVzdCBjb3JyZWxhdGlvbiBiZXR3ZWVuIHNhbXBsZXMgQSBhbmQgQiBkYXRhIHNldHMsIHdlIGNvbnNpZGVyIHRoYXQgYXMgdGhlIG9wdGltYWwgdmFsdWUsIGFuZCB3ZSBydW4gUlVWNCB1c2luZyBrID0gMjMuCgpgYGB7ciBydXY0LWsyM30KCiMjLS0tLS0tIElmIHVzaW5nIEVtcEN0cmw6CksgPSAyMwpmaXRfcnV2NF9lbXBfc2FtcGxlQSA8LSBSVVY0KFlBLCBYID0gZ0EsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGN0bCA9IEVtcF9DdF9HZW5lc19zYW1wbGVzQSRlbXBDdF9SVVYsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGsgPSBLLFogPSAxLCBldGEgPSBOVUxMLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBmdWxsVzAgPSBOVUxMLCBpbnB1dGNoZWNrID0gVFJVRSkKCmZpdF9ydXY0X2VtcF9zYW1wbGVBLnN1bW1hcnkgPC0gcnV2X3N1bW1hcnkoWUEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZml0X3J1djRfZW1wX3NhbXBsZUEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mb19zYW1wbGVzQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbXBfQ3RfR2VuZXNfc2FtcGxlc0EpCgpmaXRfcnV2NF9lbXBfc2FtcGxlQiA8LSBSVVY0KFlCLCBYID0gZ0IsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGN0bCA9IEVtcF9DdF9HZW5lc19zYW1wbGVzQiRlbXBDdF9SVVYsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGsgPSBLLFogPSAxLCBldGEgPSBOVUxMLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBmdWxsVzAgPSBOVUxMLCBpbnB1dGNoZWNrID0gVFJVRSkKCmZpdF9ydXY0X2VtcF9zYW1wbGVCLnN1bW1hcnkgPC0gcnV2X3N1bW1hcnkoWUIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZml0X3J1djRfZW1wX3NhbXBsZUIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mb19zYW1wbGVzQiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbXBfQ3RfR2VuZXNfc2FtcGxlc0IpCgojIy0tLS0tLS0gSWYgdXNpbmcgSEsgZ2VuZXM6CmZpdF9ydXY0X2hrX3NhbXBsZUEgPC0gUlVWNChZQSwgWCA9IGdBLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBjdGwgPSBjdHJsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBrID0gSyxaID0gMSwgZXRhID0gTlVMTCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZnVsbFcwID0gTlVMTCwgaW5wdXRjaGVjayA9IFRSVUUpCgpmaXRfcnV2NF9oa19zYW1wbGVBLnN1bW1hcnkgPC0gcnV2X3N1bW1hcnkoWUEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZml0X3J1djRfaGtfc2FtcGxlQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmZvX3NhbXBsZXNBKQoKZml0X3J1djRfaGtfc2FtcGxlQiA8LSBSVVY0KFlCLCBYID0gZ0IsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGN0bCA9IGN0cmwsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGsgPSBLLFogPSAxLCBldGEgPSBOVUxMLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBmdWxsVzAgPSBOVUxMLCBpbnB1dGNoZWNrID0gVFJVRSkKCmZpdF9ydXY0X2hrX3NhbXBsZUIuc3VtbWFyeSA8LSBydXZfc3VtbWFyeShZQiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaXRfcnV2NF9oa19zYW1wbGVCLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZm9fc2FtcGxlc0IpCmBgYAoKIyBDb21wYXJpc29uIG9mIHJlc3VsdHMgb2YgdW5hZGp1c3RlZCwgUlVWaW52LSBhbmQgUlVWNC1hZGp1c3RlZCBkYXRhCkluIG9yZGVyIHRvIHNlZSBpZiB3ZSBoYXZlIGhlbHBlZCBvciBub3QsIHdlIHJ1biBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcyBvbiB0aGUgKip1bmFkanVzdGVkIGRhdGEqKi4gVGhlbiB3ZSBjb21wYXJlIHRoZSByZXN1bHRzIG9mIFJVVmludiwgUlVWNCBhbmQgdW5hZGp1c3RlZCB0b2dldGhlci4KCiMjIFVuYWRqdXN0ZWQgZGF0YQpXZSBjYW4gcnVuIFJVVjQgd2l0aCBrID0gMCB0byBkbyBubyBhZGp1c3RtZW50IHdoZW4gb2J0YWluaW5nIERFR3MuCgojIyMgQXBwbHkgREUgYW5hbHlzaXMgaW4gdGhlIHVuYWRqdXN0ZWQgZGF0YSB1c2luZyBISyBnZW5lcwpgYGB7ciBERS11bmFkanVzdGVkLUEtQi11c2luZy1IS30KIyBSVVY0IHdpdGggayA9IDAgZm9yIG5vIGFkanVzdG1lbnQKIyBFcXVpdmFsZW50IHRvIGEgTGltbWEgQW5hbHlzaXMgd2l0aG91dCBjb25zaWRlcmluZyB0aGUgYmF0Y2ggdGVybQoKIyMtLS0tLSBJbiBzYW1wbGUgQSBkYXRhCmZpdF91bmFkal9oa19zYW1wbGVBIDwtIFJVVjQoWUEsIFggPSBnQSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgY3RsID0gY3RybCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgayA9IDApCmZpdF91bmFkal9oa19zYW1wbGVBLnN1bW1hcnkgPC0gcnV2X3N1bW1hcnkoWUEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZml0X3VuYWRqX2hrX3NhbXBsZUEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmZvX3NhbXBsZXNBKQoKIyMtLS0tLSBJbiBzYW1wbGUgQiBkYXRhCmZpdF91bmFkal9oa19zYW1wbGVCIDwtIFJVVjQoWUIsIFggPSBnQiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgY3RsID0gY3RybCwKICAgICAgICAgICAgICAgICAgICAgICAgICBrID0gMCkKZml0X3VuYWRqX2hrX3NhbXBsZUIuc3VtbWFyeSA8LSBydXZfc3VtbWFyeShZQiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZml0X3VuYWRqX2hrX3NhbXBsZUIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mb19zYW1wbGVzQikKCmBgYAoKIyMjIEFwcGx5IERFIGFuYWx5c2lzIGluIHRoZSB1bmFkanVzdGVkIGRhdGEgdXNpbmcgZW1waXJpY2FsIGNvbnRyb2wgZ2VuZXMKYGBge3IgREUtdW5hZGp1c3RlZC1BLUItdXNpbmctRW1wcmljYWxDdGx9CiMgUlVWNCB3aXRoIGsgPSAwIGZvciBubyBhZGp1c3RtZW50CiMgRXF1aXZhbGVudCB0byBhIExpbW1hIEFuYWx5c2lzIHdpdGhvdXQgY29uc2lkZXJpbmcgdGhlIGJhdGNoIHRlcm0KCiMjLS0tLS0gSW4gc2FtcGxlIEEgZGF0YQpmaXRfdW5hZGpfZW1wX3NhbXBsZUEgPC0gUlVWNChZQSwgWCA9IGdBLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBjdGwgPSBFbXBfQ3RfR2VuZXNfc2FtcGxlc0EkZW1wQ3RfUlVWLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBrID0gMCkKZml0X3VuYWRqX2VtcF9zYW1wbGVBLnN1bW1hcnkgPC0gcnV2X3N1bW1hcnkoWUEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZml0X3VuYWRqX2VtcF9zYW1wbGVBLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mb19zYW1wbGVzQSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbXBfQ3RfR2VuZXNfc2FtcGxlc0EpCgojIy0tLS0tIEluIHNhbXBsZSBCIGRhdGEKZml0X3VuYWRqX2VtcF9zYW1wbGVCIDwtIFJVVjQoWUIsIFggPSBnQiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgY3RsID0gRW1wX0N0X0dlbmVzX3NhbXBsZXNCJGVtcEN0X1JVViwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgayA9IDApCmZpdF91bmFkal9lbXBfc2FtcGxlQi5zdW1tYXJ5IDwtIHJ1dl9zdW1tYXJ5KFlCLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaXRfdW5hZGpfZW1wX3NhbXBsZUIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mb19zYW1wbGVzQiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbXBfQ3RfR2VuZXNfc2FtcGxlc0IpCgpgYGAKCiMjIFAtdmFsdWVzIGRpc3RyaWJ1dGlvbgpXZSBjb21wYXJlIHRoZSByZXN1bHRzIG9idGFpbmVkIGZyb20gdW5hanVzdGVkLCBSVVZpbnYtIGFuZCBSVVY0LSBhZGp1c3RlZCBkYXRhIHVzaW5nIHAtdmFsdWUgZGlzdHJpYnV0aW9ucywgY29ycmVsYXRpb25zIG9mIGJldGEgdmFsdWVzIGFuZCB2ZW5uIGRpYWdyYW1zIGluIHNhbXBsZXMgQSBhbmQgQiBkYXRhLgoKYGBge3J9CgpydXZfaGlzdChmaXRfdW5hZGpfZW1wX3NhbXBsZUEuc3VtbWFyeSkgKyBnZ3RpdGxlKCJVbmFkal9BIikKcnV2X2hpc3QoZml0X3VuYWRqX2VtcF9zYW1wbGVCLnN1bW1hcnkpICsgZ2d0aXRsZSgiVW5hZGpfQiIpCiMgcnV2X2hpc3QoZml0X3VuYWRqX2hrX3NhbXBsZUEuc3VtbWFyeSkKIyBydXZfaGlzdChmaXRfdW5hZGpfaGtfc2FtcGxlQi5zdW1tYXJ5KQoKcnV2X2hpc3QoZml0X3J1dmluX2hrX3NhbXBsZXNBLnN1bW1hcnkpICsgZ2d0aXRsZSgiUlVWaW52X0hLX0EiKQpydXZfaGlzdChmaXRfcnV2aW5faGtfc2FtcGxlc0Iuc3VtbWFyeSkgKyBnZ3RpdGxlKCJSVVZpbnZfSEtfQiIpCnJ1dl9oaXN0KGZpdF9ydXZpbl9lbXBfc2FtcGxlc0Euc3VtbWFyeSkgKyBnZ3RpdGxlKCJSVVZpbnZfRW1wX0EiKQpydXZfaGlzdChmaXRfcnV2aW5fZW1wX3NhbXBsZXNCLnN1bW1hcnkpICsgZ2d0aXRsZSgiUlVWaW52X0VtcF9CIikKCnJ1dl9oaXN0KGZpdF9ydXY0X2hrX3NhbXBsZUEuc3VtbWFyeSkgKyBnZ3RpdGxlKCJSVVY0X0hLX0EiKQpydXZfaGlzdChmaXRfcnV2NF9oa19zYW1wbGVCLnN1bW1hcnkpICsgZ2d0aXRsZSgiUlVWNF9IS19CIikKcnV2X2hpc3QoZml0X3J1djRfZW1wX3NhbXBsZUEuc3VtbWFyeSkgKyBnZ3RpdGxlKCJSVVY0X0VtcF9BIikKcnV2X2hpc3QoZml0X3J1djRfZW1wX3NhbXBsZUIuc3VtbWFyeSkgKyBnZ3RpdGxlKCJSVVY0X0VtcF9CIikKCmBgYAoKIyMgQmV0YWhhdCBjb3JyZWxhdGlvbgpGb3IgZWFjaCBvZiB0aGUgdW5hZGp1c3RlZCwgUlVWaW52LSBhbmQgUlVWNC0gYWRqdXN0ZWQgc2V0dGluZ3MsIHdlIGNhbiBjb21wYXJlIHRoZSByZXN1bHRzIGJldHdlZW4gc2FtcGxlcyBBIGFuZCBCIGRhdGEgc2V0cyB0byBzZWUgd2hpY2ggbWV0aG9kIGdpdmVzIG1vcmUgY29uc2lzdGVudCByZXN1bHN0IGluIHRoZXNlIHR3byBkYXRhIHNldHMuIFRvIHF1YW50aWZ5IHRoZXNlIGNvbnNpc3RlbmNpZXMsIHdlIGxvb2sgYXQgdGhlIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIGJldGFoYXQgZnJvbSBzYW1wbGUgQSBhbmQgYmV0YWhhdCBmcm9tIHNhbXBsZSBCIGZvciB0aGUgdW5hZGp1c3RlZCBtZXRob2QsIFJVVmludiBhbmQgUlVWNC4KCmBgYHtyIGNvci1iZXRhaGF0LUEtQi1FbXBDdGx9CiMjLS0tLS0tIFVuYWRqdXN0ZWQgZGF0YSBzZXRzCnBsb3QoZml0X3VuYWRqX2VtcF9zYW1wbGVBJGJldGFoYXQsIAogICAgIGZpdF91bmFkal9lbXBfc2FtcGxlQiRiZXRhaGF0LAogICAgIHhsYWIgPSAiQmV0YWhhdCBTYW1wbGVzIEEiLAogICAgIHlsYWIgPSAiQmV0YWhhdCBTYW1wbGVzIEIiLAogICAgIG1haW4gPSAiVW5hZGp1c3RlZCIsCiAgICAgeGxpbSA9IGMoLTMsMyksIGNleCA9IDAuMywgeWxpbSA9IGMoLTQsNCkpCmNvclZhbCA8LSBjb3IudGVzdChmaXRfdW5hZGpfZW1wX3NhbXBsZUEkYmV0YWhhdCwgZml0X3VuYWRqX2VtcF9zYW1wbGVCJGJldGFoYXQpJGVzdGltYXRlCnRleHQoLTMsMywgcG9zID0gNCwgcGFzdGUoIkNvcnJlbGF0aW9uOiAiLCByb3VuZChjb3JWYWwsMiksIHNlcCA9ICIiKSkKCiMjLS0tLS0tIFJVVmludiBhZGp1c3RlZCBkYXRhIHNldHMKcGxvdChmaXRfcnV2aW5fZW1wX3NhbXBsZXNBJGJldGFoYXQsCiAgICAgZml0X3J1dmluX2VtcF9zYW1wbGVzQiRiZXRhaGF0LAogICAgIHhsYWIgPSAiQmV0YWhhdCBTYW1wbGVzIEEiLAogICAgIHlsYWIgPSAiQmV0YWhhdCBTYW1wbGVzIEIiLAogICAgIG1haW4gPSAiUlVWaW52IiwKICAgICB4bGltID0gYygtMywzKSwgY2V4PTAuMywgeWxpbT1jKC00LDQpKQpjb3JWYWwgPC0gY29yLnRlc3QoZml0X3J1dmluX2VtcF9zYW1wbGVzQSRiZXRhaGF0LCBmaXRfcnV2aW5fZW1wX3NhbXBsZXNCJGJldGFoYXQpJGVzdGltYXRlCnRleHQoLTMsMywgcG9zID0gNCwgcGFzdGUoIkNvcnJlbGF0aW9uOiAiLCByb3VuZChjb3JWYWwsMiksIHNlcCA9ICIiKSkKCiMtLS0tLS0tIFJVVjQgYWRqdXN0ZWQgZGF0YSBzZXRzCnBsb3QoZml0X3J1djRfZW1wX3NhbXBsZUEkYmV0YWhhdCwKICAgICBmaXRfcnV2NF9lbXBfc2FtcGxlQiRiZXRhaGF0LAogICAgIHhsYWIgPSAiQmV0YWhhdCBTYW1wbGVzIEEiLAogICAgIHlsYWIgPSAiQmV0YWhhdCBTYW1wbGVzIEIiLAogICAgIG1haW4gPSAiUlVWNCIsCiAgICAgeGxpbSA9IGMoLTMsMyksIGNleCA9IDAuMywgeWxpbSA9IGMoLTQsNCkpCiNhYmxpbmUoZml0X3J1djRfZW1wX3NhbXBsZUIkYmV0YWhhdCxmaXRfcnV2NF9lbXBfc2FtcGxlQSRiZXRhaGF0KQpjb3JWYWwgPC0gY29yLnRlc3QoZml0X3J1djRfZW1wX3NhbXBsZUEkYmV0YWhhdCwgZml0X3J1djRfZW1wX3NhbXBsZUIkYmV0YWhhdCkkZXN0aW1hdGUKdGV4dCgtMywzLCBwb3M9NCwgcGFzdGUoIkNvcnJlbGF0aW9uOiAiLCByb3VuZChjb3JWYWwsMiksc2VwPSIiKSkKCmBgYAoKIyMgT3ZlcmxhcCBiZXR3ZWVuIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyAKRmluYWxseSwgZm9yIGVhY2ggb2YgdGhlIHVuYWRqdXN0ZWQsIFJVVmludiBhbmQgUlVWNCwgd2UgbG9vayBhdCB0aGUgbnVtYmVyIG9mIG92ZXJsYXBwaW5nIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyAoREVHcykgYmV0d2VlbiB0aGUgdHdvIHNhbXBsZXMgQSBhbmQgQiBkYXRhIHNldHMuIFdlIGFsc28gY2hlY2sgZm9yIGNvbnNpc3RlbmN5IGJldHdlZW4gbWV0aG9kcyBvbiB0aGUgc2FtZSBkYXRhIChzYW1wbGUgQSBvciBzYW1wbGUgQiBkYXRhIHNldCkuXAoKRmlyc3QsIHdlIGRlZmluZSBERUdzIGFzIGdlbmVzIHdpdGggYWRqdXN0ZWQgcC12YWx1ZSA8IDAuMDUgYW5kIHxsb2dGQ3wgPiAxIGluIHNhbXBsZXMgQSBhbmQgQiBkYXRhIHNldHMgd2hpY2ggYXJlIHVuYWRqdXN0ZWQsIFJVVjQtIG9yIFJVVmludi1hZGp1c3RlZC4KCmBgYHtyfQojIy0tLS0tLSBJbiBzYW1wbGUgQSBkYXRhCkRFR3NVbmFkal9zYW1wbGVBIDwtIHJvdy5uYW1lcyhmaXRfdW5hZGpfZW1wX3NhbXBsZUEuc3VtbWFyeSRDKVtmaXRfdW5hZGpfZW1wX3NhbXBsZUEuc3VtbWFyeSRDJEYucC5CSCA8IDAuMDUgJiBhYnMoZml0X3VuYWRqX2VtcF9zYW1wbGVBLnN1bW1hcnkkQyRiX1gxKSA+IDFdCgpERUdzUlVWaW52X3NhbXBsZUEgPC0gcm93Lm5hbWVzKGZpdF9ydXZpbl9lbXBfc2FtcGxlc0Euc3VtbWFyeSRDKVtmaXRfcnV2aW5fZW1wX3NhbXBsZXNBLnN1bW1hcnkkQyRGLnAuQkggPCAwLjA1ICYgYWJzKGZpdF9ydXZpbl9lbXBfc2FtcGxlc0Euc3VtbWFyeSRDJGJfWDEpID4gMV0KCkRFR3NSVVY0X3NhbXBsZUEgPC0gcm93Lm5hbWVzKGZpdF9ydXY0X2VtcF9zYW1wbGVBLnN1bW1hcnkkQylbZml0X3J1djRfZW1wX3NhbXBsZUEuc3VtbWFyeSRDJEYucC5CSCA8IDAuMDUgJiBhYnMoZml0X3J1djRfZW1wX3NhbXBsZUEuc3VtbWFyeSRDJGJfWDEpID4gMV0gIAoKIyMtLS0tLS0gSW4gc2FtcGxlIEIgZGF0YToKREVHc1VuYWRqX3NhbXBsZUIgPC0gcm93Lm5hbWVzKGZpdF91bmFkal9lbXBfc2FtcGxlQi5zdW1tYXJ5JEMpW2ZpdF91bmFkal9lbXBfc2FtcGxlQi5zdW1tYXJ5JEMkRi5wLkJIIDwgMC4wNSAmIGFicyhmaXRfdW5hZGpfZW1wX3NhbXBsZUIuc3VtbWFyeSRDJGJfWDEpID4gMV0KCkRFR3NSVVZpbnZfc2FtcGxlQjwtIHJvdy5uYW1lcyhmaXRfcnV2aW5fZW1wX3NhbXBsZXNCLnN1bW1hcnkkQylbZml0X3J1dmluX2VtcF9zYW1wbGVzQi5zdW1tYXJ5JEMkRi5wLkJIIDwgMC4wNSAmIGFicyhmaXRfcnV2aW5fZW1wX3NhbXBsZXNCLnN1bW1hcnkkQyRiX1gxKSA+IDFdIAoKREVHc1JVVjRfc2FtcGxlQiA8LSByb3cubmFtZXMoZml0X3J1djRfZW1wX3NhbXBsZUIuc3VtbWFyeSRDKVtmaXRfcnV2NF9lbXBfc2FtcGxlQi5zdW1tYXJ5JEMkRi5wLkJIIDwgMC4wNSAmIGFicyhmaXRfcnV2NF9lbXBfc2FtcGxlQi5zdW1tYXJ5JEMkYl9YMSkgPiAxXSAgCmBgYAoKIyMjIERFR3MgaW4gdGhlIHVuYWRqdXN0ZWQgZGF0YQpWZW5uIGRpYWdyYW0gY29tcGFyaW5nIHRoZSB1bmFkanVzdGVkIHNhbXBsZXMgQSBhbmQgQiBkYXRhLgpgYGB7ciBWZW5uLURFR3MtdW5hZGp9CmFsbERFR3NfdW5hZGogPC0gYyhERUdzVW5hZGpfc2FtcGxlQSwgCiAgICAgICAgICAgICAgICAgICAgREVHc1VuYWRqX3NhbXBsZUIpCgojIyByZW1vdmUgZHVwbGljYXRlZCBnZW5lIHN5bWJvbHM6CmFsbERFR3NfdW5hZGogPC0gYWxsREVHc191bmFkalshZHVwbGljYXRlZChhbGxERUdzX3VuYWRqKV0gIAoKIyMgRHJhdyBhIFZlbm4gZGlhZ3JhbSBjb21wYXJpbmcgREVHcyBmb3IgUlVWaW52CkNvdW50c191bmFkaiA8LSBtYXRyaXgoMCwgbnJvdyA9IGxlbmd0aChhbGxERUdzX3VuYWRqKSwgbmNvbCA9IDIpCnJvdy5uYW1lcyhDb3VudHNfdW5hZGopPC0gYWxsREVHc191bmFkagpjb2xuYW1lcyhDb3VudHNfdW5hZGopPC0gYygiVW5hZGpfQSIsIlVuYWRqX0IiKQoKZm9yKCBpIGluIDE6bGVuZ3RoKGFsbERFR3NfdW5hZGopKSB7CiAgQ291bnRzX3VuYWRqW2ksMV08LSBhbGxERUdzX3VuYWRqW2ldICVpbiUgREVHc1VuYWRqX3NhbXBsZUEKICBDb3VudHNfdW5hZGpbaSwyXTwtIGFsbERFR3NfdW5hZGpbaV0gJWluJSBERUdzVW5hZGpfc2FtcGxlQgp9Cgpjb2wgPC0gYygiYmx1ZSIsICJ2aW9sZXQiKQp2ZW5uRGlhZ3JhbSh2ZW5uQ291bnRzKENvdW50c191bmFkaiksIAogICAgICAgICAgICBjaXJjbGUuY29sID0gY29sLCAKICAgICAgICAgICAgY2V4ID0gYygxLjYsIDEuMiwgMSksIGx3ZD0yKQoKYGBgCgojIyMgREVHcyBpbiB0aGUgUlVWaW52LWFkanVzdGVkIGRhdGEKVmVubiBkaWFncmFtIGNvbXBhcmluZyB0aGUgUlVWaW52LWFkanVzdGVkIHNhbXBsZXMgQSBhbmQgQiBkYXRhLgpgYGB7ciBWZW5uLURFR3MtUlVWaW52fQoKYWxsREVHc19SVVZpbnYgPC0gYyhERUdzUlVWaW52X3NhbXBsZUEsIAogICAgICAgICAgICAgICAgICAgIERFR3NSVVZpbnZfc2FtcGxlQikKCiMjIHJlbW92ZSBkdXBsaWNhdGVkIGdlbmUgc3ltYm9sczoKYWxsREVHc19SVVZpbnYgPC0gYWxsREVHc19SVVZpbnZbIWR1cGxpY2F0ZWQoYWxsREVHc19SVVZpbnYpXSAgCgojIyBEcmF3IGEgVmVubiBkaWFncmFtIGNvbXBhcmluZyBERUdzIGZvciBSVVZpbnYKQ291bnRzX1JVVmludiA8LSBtYXRyaXgoMCwgbnJvdyA9IGxlbmd0aChhbGxERUdzX1JVVmludiksIG5jb2wgPSAyKQpyb3cubmFtZXMoQ291bnRzX1JVVmludik8LSBhbGxERUdzX1JVVmludgpjb2xuYW1lcyhDb3VudHNfUlVWaW52KTwtIGMoIlJVVmludl9BIiwiUlVWaW52X0IiKQoKZm9yKCBpIGluIDE6bGVuZ3RoKGFsbERFR3NfUlVWaW52KSkgewogIENvdW50c19SVVZpbnZbaSwxXTwtIGFsbERFR3NfUlVWaW52W2ldICVpbiUgREVHc1JVVmludl9zYW1wbGVBCiAgQ291bnRzX1JVVmludltpLDJdPC0gYWxsREVHc19SVVZpbnZbaV0gJWluJSBERUdzUlVWaW52X3NhbXBsZUIKfQoKY29sPC0gYygiYmx1ZSIsICJ2aW9sZXQiKQp2ZW5uRGlhZ3JhbSh2ZW5uQ291bnRzKENvdW50c19SVVZpbnYpLCAKICAgICAgICAgICAgY2lyY2xlLmNvbCA9IGNvbCwKICAgICAgICAgICAgY2V4ID0gYygxLjYsIDEuMiwgMSksIGx3ZCA9IDIpCgpgYGAKCiMjIyBERUdzIGluIHRoZSBSVVY0LWFkanVzdGVkIGRhdGEKVmVubiBkaWFncmFtIGNvbXBhcmluZyB0aGUgUlVWNC1hZGp1c3RlZCBzYW1wbGVzIEEgYW5kIEIgZGF0YS4KYGBge3IgVmVubi1ERUdzLVJVVjR9CgphbGxERUdzX1JVVjQ8LSBjKERFR3NSVVY0X3NhbXBsZUEsIERFR3NSVVY0X3NhbXBsZUIpCgojIyByZW1vdmUgZHVwbGljYXRlZCBnZW5lIHN5bWJvbHM6CmFsbERFR3NfUlVWNDwtIGFsbERFR3NfUlVWNFshZHVwbGljYXRlZChhbGxERUdzX1JVVjQpXSAgCgojIyBEcmF3IGEgVmVubiBkaWFncmFtIGNvbXBhcmluZyBERUdzIGZvciBSVVY0CkNvdW50c19SVVY0IDwtIG1hdHJpeCgwLCBucm93PSBsZW5ndGgoYWxsREVHc19SVVY0KSwgbmNvbD0yKQpyb3cubmFtZXMoQ291bnRzX1JVVjQpPC0gYWxsREVHc19SVVY0CmNvbG5hbWVzKENvdW50c19SVVY0KTwtIGMoIlJVVjRfQSIsIlJVVjRfQiIpCgpmb3IoIGkgaW4gMTpsZW5ndGgoYWxsREVHc19SVVY0KSkgewogIENvdW50c19SVVY0W2ksMV08LSBhbGxERUdzX1JVVjRbaV0gJWluJSBERUdzUlVWNF9zYW1wbGVBCiAgQ291bnRzX1JVVjRbaSwyXTwtIGFsbERFR3NfUlVWNFtpXSAlaW4lIERFR3NSVVY0X3NhbXBsZUIKfQoKY29sPC0gYygiYmx1ZSIsICJ2aW9sZXQiKQp2ZW5uRGlhZ3JhbSh2ZW5uQ291bnRzKENvdW50c19SVVY0KSwgCiAgICAgICAgICAgIGNpcmNsZS5jb2wgPSBjb2wsIAogICAgICAgICAgICBjZXggPSBjKDEuNiwgMS4yLCAxKSwgbHdkID0gMikKYGBgCgojIyMgQ29tcGFyZSB0aGUgdW5hZGp1c3RlZCwgUlVWNCBhbmQgUlVWaW52LWFkanVzdGVkIGluIHNhbXBsZXMgQSBkYXRhCmBgYHtyIFZlbm4tREVHcy1zYW1wbGVzQX0KCmFsbERFR3Nfc2FtcGxlQSA8LSBjKERFR3NVbmFkal9zYW1wbGVBLCBERUdzUlVWaW52X3NhbXBsZUEsIERFR3NSVVY0X3NhbXBsZUEpCgojIyByZW1vdmUgZHVwbGljYXRlZCBnZW5lIHN5bWJvbHM6CmFsbERFR3Nfc2FtcGxlQSA8LSBhbGxERUdzX3NhbXBsZUFbIWR1cGxpY2F0ZWQoYWxsREVHc19zYW1wbGVBKV0gIAoKIyMgRHJhdyBhIFZlbm4gZGlhZ3JhbSBjb21wYXJpbmcgREVHcyBmb3Igc2FtcGxlIEEKQ291bnRzX3NhbXBsZUEgPC0gbWF0cml4KDAsIG5yb3c9IGxlbmd0aChhbGxERUdzX3NhbXBsZUEpLCBuY29sPTMpCnJvdy5uYW1lcyhDb3VudHNfc2FtcGxlQSk8LSBhbGxERUdzX3NhbXBsZUEKY29sbmFtZXMoQ291bnRzX3NhbXBsZUEpPC0gYygiVW5hZGpfQSIsICJSVVZpbnZfQSIsICJSdXY0X0EiKQoKZm9yKCBpIGluIDE6bGVuZ3RoKGFsbERFR3Nfc2FtcGxlQSkpIHsKICBDb3VudHNfc2FtcGxlQVtpLDFdPC0gYWxsREVHc19zYW1wbGVBW2ldICVpbiUgREVHc1VuYWRqX3NhbXBsZUEKICBDb3VudHNfc2FtcGxlQVtpLDJdPC0gYWxsREVHc19zYW1wbGVBW2ldICVpbiUgREVHc1JVVmludl9zYW1wbGVBCiAgQ291bnRzX3NhbXBsZUFbaSwzXTwtIGFsbERFR3Nfc2FtcGxlQVtpXSAlaW4lIERFR3NSVVY0X3NhbXBsZUEKfQoKY29sPC0gYygiYmx1ZSIsICJ2aW9sZXQiLCAiZGFya2dyZWVuIikKdmVubkRpYWdyYW0odmVubkNvdW50cyhDb3VudHNfc2FtcGxlQSksIAogICAgICAgICAgICBjaXJjbGUuY29sPWNvbCwgCiAgICAgICAgICAgIGNleD1jKDEuNiwgMS4yLCAxKSwgbHdkPTIpCgpgYGAKCiMjIyBDb21wYXJlIHRoZSB1bmFkanVzdGVkLCBSVVY0IGFuZCBSVVZpbnYtYWRqdXN0ZWQgaW4gc2FtcGxlcyBCIGRhdGEKYGBge3IgVmVubi1ERUdzLXNhbXBsZXNCfQoKYWxsREVHc19zYW1wbGVCIDwtIGMoREVHc1VuYWRqX3NhbXBsZUIsCiAgICAgICAgICAgICAgICAgICAgIERFR3NSVVZpbnZfc2FtcGxlQiwKICAgICAgICAgICAgICAgICAgICAgREVHc1JVVjRfc2FtcGxlQikKCiMjIHJlbW92ZSBkdXBsaWNhdGVkIGdlbmUgc3ltYm9sczoKYWxsREVHc19zYW1wbGVCIDwtIGFsbERFR3Nfc2FtcGxlQlshZHVwbGljYXRlZChhbGxERUdzX3NhbXBsZUIpXSAKCiMjIERyYXcgYSBWZW5uIGRpYWdyYW0gY29tcGFyaW5nIERFR3MgZm9yIHNhbXBsZSBCCkNvdW50c19zYW1wbGVCIDwtIG1hdHJpeCgwLCBucm93ID0gbGVuZ3RoKGFsbERFR3Nfc2FtcGxlQiksIG5jb2wgPSAzKQpyb3cubmFtZXMoQ291bnRzX3NhbXBsZUIpIDwtIGFsbERFR3Nfc2FtcGxlQgpjb2xuYW1lcyhDb3VudHNfc2FtcGxlQikgPC0gYygiVW5hZGpfQiIsICJSVVZpbnZfQiIsIlJ1djRfQiIpCgpmb3IoIGkgaW4gMTpsZW5ndGgoYWxsREVHc19zYW1wbGVCKSkgewogIENvdW50c19zYW1wbGVCW2ksMV08LSBhbGxERUdzX3NhbXBsZUJbaV0gJWluJSBERUdzVW5hZGpfc2FtcGxlQgogIENvdW50c19zYW1wbGVCW2ksMl08LSBhbGxERUdzX3NhbXBsZUJbaV0gJWluJSBERUdzUlVWaW52X3NhbXBsZUIKICBDb3VudHNfc2FtcGxlQltpLDNdPC0gYWxsREVHc19zYW1wbGVCW2ldICVpbiUgREVHc1JVVjRfc2FtcGxlQgp9Cgpjb2wgPC0gYygiYmx1ZSIsICJ2aW9sZXQiLCAiZGFya2dyZWVuIikKdmVubkRpYWdyYW0odmVubkNvdW50cyhDb3VudHNfc2FtcGxlQiksIAogICAgICAgICAgICBjaXJjbGUuY29sID0gY29sLCAKICAgICAgICAgICAgY2V4ID0gYygxLjYsIDEuMiwgMSksIGx3ZCA9IDIpCmBgYAoKCgoKCgoK